From 2c907fe3df6ed58c4fb2798cbff840ecd1fc9bd4 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Mon, 19 Aug 2024 15:28:55 +0000 Subject: [PATCH 001/292] added communities creation --- backend/src/create_communities.py | 132 ++++++++++++++++++++++++++++++ backend/src/llm.py | 2 + backend/src/shared/common_fn.py | 4 +- 3 files changed, 136 insertions(+), 2 deletions(-) create mode 100644 backend/src/create_communities.py diff --git a/backend/src/create_communities.py b/backend/src/create_communities.py new file mode 100644 index 000000000..816dc9765 --- /dev/null +++ b/backend/src/create_communities.py @@ -0,0 +1,132 @@ +import os +from langchain_community.graphs import Neo4jGraph +from graphdatascience import GraphDataScience +import pandas as pd +import numpy as np +from langchain_core.prompts import ChatPromptTemplate +from langchain_core.output_parsers import StrOutputParser +from src.llm import get_llm + +import os +import getpass +from neo4j import GraphDatabase, Result +import pandas as pd +import seaborn as sns +import matplotlib.pyplot as plt +import tiktoken +import numpy as np +from langchain_openai import OpenAIEmbeddings, ChatOpenAI +from langchain_community.vectorstores import Neo4jVector +from langchain_community.graphs import Neo4jGraph +from langchain_core.prompts import ChatPromptTemplate +from langchain_core.output_parsers import StrOutputParser + +from tqdm import tqdm +from src.shared.common_fn import load_embedding_model + + +from typing import Dict, Any +from concurrent.futures import ThreadPoolExecutor, as_completed +from tqdm import tqdm +from src.llm import get_llm + +import logging +from graphdatascience import GraphDataScience + +COMMUNITY_PROJECT_NAME = "communities" +NODE_PROJECTION = "__Entity__" +CREATE_COMMUNITY_CONSTRAINT = "CREATE CONSTRAINT IF NOT EXISTS FOR (c:__Community__) REQUIRE c.id IS UNIQUE;" + +def get_gds_driver(uri, username, password, database): + try: + gds = GraphDataScience( + endpoint=uri, + auth=(username, password), + database=database + ) + logging.info("Successfully created GDS driver.") + return gds + except Exception as e: + logging.error(f"Failed to create GDS driver: {e}") + raise + +def create_community_graph_project(gds, project_name=COMMUNITY_PROJECT_NAME, node_projection=NODE_PROJECTION): + try: + existing_projects = gds.graph.list() + project_exists = existing_projects["graphName"].str.contains(project_name, regex=False).any() + + if project_exists: + logging.info(f"Project '{project_name}' already exists. Dropping it.") + gds.graph.drop(project_name) + + logging.info(f"Creating new graph project '{project_name}'.") + graph_project, result = gds.graph.project( + project_name, + node_projection, + { + "_ALL_": { + "type": "*", + "orientation": "UNDIRECTED", + "properties": { + "weight": { + "property": "*", + "aggregation": "COUNT" + } + } + } + } + ) + logging.info(f"Graph project '{project_name}' created successfully.") + return graph_project, result + except Exception as e: + logging.error(f"Failed to create community graph project: {e}") + raise + +def write_communities(gds, graph_project, project_name=COMMUNITY_PROJECT_NAME): + try: + logging.info(f"Writing communities to the graph project '{project_name}'.") + gds.leiden.write( + graph_project, + writeProperty=project_name, + includeIntermediateCommunities=True, + relationshipWeightProperty="weight" + ) + logging.info("Communities written successfully.") + return True + except Exception as e: + logging.error(f"Failed to write communities: {e}") + return False + + + + +def create_communities(uri, username, password, database,graph): + try: + gds = get_gds_driver(uri, username, password, database) + graph_project, result = create_community_graph_project(gds) + + if write_communities(gds, graph_project): + logging.info("Applying community constraint to the graph.") + graph.query(CREATE_COMMUNITY_CONSTRAINT) + # Optionally, you can call create_community_properties() here if needed + logging.info("Communities creation process completed successfully.") + else: + logging.warning("Failed to write communities. Constraint was not applied.") + except Exception as e: + logging.error(f"Failed to create communities: {e}") + + + +# def create_communities(uri,username,password,database,graph): +# gds = get_gds_driver(uri,username,password,database) +# graph_project,result = create_community_graph_project(gds) +# result1 = write_communities(gds,graph_project) +# if result1: +# graph.query(CREATE_COMMUNITY_CONSTRAINT) +# # create_community_properties() + + + + + + diff --git a/backend/src/llm.py b/backend/src/llm.py index 0ee61b650..505bb89fb 100644 --- a/backend/src/llm.py +++ b/backend/src/llm.py @@ -153,9 +153,11 @@ def get_graph_document_list( node_properties = False else: node_properties = ["description"] + relationship_properties = ["description"] llm_transformer = LLMGraphTransformer( llm=llm, node_properties=node_properties, + relationship_properties=relationship_properties, allowed_nodes=allowedNodes, allowed_relationships=allowedRelationship, ) diff --git a/backend/src/shared/common_fn.py b/backend/src/shared/common_fn.py index b0dbe2f5f..6d24912c7 100644 --- a/backend/src/shared/common_fn.py +++ b/backend/src/shared/common_fn.py @@ -94,8 +94,8 @@ def load_embedding_model(embedding_model_name: str): return embeddings, dimension def save_graphDocuments_in_neo4j(graph:Neo4jGraph, graph_document_list:List[GraphDocument]): - # graph.add_graph_documents(graph_document_list, baseEntityLabel=True) - graph.add_graph_documents(graph_document_list) + graph.add_graph_documents(graph_document_list, baseEntityLabel=True,include_source=True) + # graph.add_graph_documents(graph_document_list) def handle_backticks_nodes_relationship_id_type(graph_document_list:List[GraphDocument]): for graph_document in graph_document_list: From 7081f13b5730b3ec3d60637a3df50d31176c3220 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Tue, 20 Aug 2024 11:49:50 +0000 Subject: [PATCH 002/292] added communities --- backend/score.py | 8 + backend/src/communities.py | 253 +++ backend/src/create_communities.py | 132 -- experiments/graphrag.ipynb | 3519 +++++++++++++++++++++++++++++ 4 files changed, 3780 insertions(+), 132 deletions(-) create mode 100644 backend/src/communities.py delete mode 100644 backend/src/create_communities.py create mode 100644 experiments/graphrag.ipynb diff --git a/backend/score.py b/backend/score.py index 6f5113db6..7a2ab16c7 100644 --- a/backend/score.py +++ b/backend/score.py @@ -16,6 +16,7 @@ from src.chunkid_entities import get_entities_from_chunkids from src.post_processing import create_fulltext, create_entity_embedding from sse_starlette.sse import EventSourceResponse +from src.communities import create_communities import json from typing import List, Mapping from starlette.middleware.sessions import SessionMiddleware @@ -241,6 +242,13 @@ async def post_processing(uri=Form(), userName=Form(), password=Form(), database graph = create_graph_database_connection(uri, userName, password, database) tasks = set(map(str.strip, json.loads(tasks))) + if "create_communities" in tasks: + model = "openai-gpt-4o" + await asyncio.to_thread(create_communities, uri, userName, password, database,graph,model) + josn_obj = {'api_name': 'post_processing/create_communities', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(josn_obj) + logging.info(f'created communities') + if "materialize_text_chunk_similarities" in tasks: await asyncio.to_thread(update_graph, graph) josn_obj = {'api_name': 'post_processing/materialize_text_chunk_similarities', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} diff --git a/backend/src/communities.py b/backend/src/communities.py new file mode 100644 index 000000000..e2f09cba6 --- /dev/null +++ b/backend/src/communities.py @@ -0,0 +1,253 @@ +import logging +from graphdatascience import GraphDataScience +from src.llm import get_llm +from langchain_core.prompts import ChatPromptTemplate +from langchain_core.output_parsers import StrOutputParser +from tqdm import tqdm +from concurrent.futures import ThreadPoolExecutor, as_completed +from tqdm import tqdm + + +COMMUNITY_PROJECT_NAME = "communities" +NODE_PROJECTION = "__Entity__" +MAX_WORKERS = 10 + +CREATE_COMMUNITY_CONSTRAINT = "CREATE CONSTRAINT IF NOT EXISTS FOR (c:__Community__) REQUIRE c.id IS UNIQUE;" +CREATE_COMMUNITY_LEVELS = """ +MATCH (e:`__Entity__`) +UNWIND range(0, size(e.communities) - 1 , 1) AS index +CALL { + WITH e, index + WITH e, index + WHERE index = 0 + MERGE (c:`__Community__` {id: toString(index) + '-' + toString(e.communities[index])}) + ON CREATE SET c.level = index + MERGE (e)-[:IN_COMMUNITY]->(c) + RETURN count(*) AS count_0 +} +CALL { + WITH e, index + WITH e, index + WHERE index > 0 + MERGE (current:`__Community__` {id: toString(index) + '-' + toString(e.communities[index])}) + ON CREATE SET current.level = index + MERGE (previous:`__Community__` {id: toString(index - 1) + '-' + toString(e.communities[index - 1])}) + ON CREATE SET previous.level = index - 1 + MERGE (previous)-[:IN_COMMUNITY]->(current) + RETURN count(*) AS count_1 +} +RETURN count(*) +""" +CREATE_COMMUNITY_RANKS = """ +MATCH (c:__Community__)<-[:IN_COMMUNITY*]-(:__Entity__)<-[:MENTIONS]-(d:Document) +WITH c, count(distinct d) AS rank +SET c.community_rank = rank; +""" + +CREATE_COMMUNITY_WEIGHTS = """ +MATCH (n:`__Community__`)<-[:IN_COMMUNITY]-()<-[:HAS_ENTITY]-(c) +WITH n, count(distinct c) AS chunkCount +SET n.weight = chunkCount""" + +GET_COMMUNITY_INFO = """ +MATCH (c:`__Community__`)<-[:IN_COMMUNITY*]-(e:__Entity__) +WHERE c.level IN [0,1,4] +WITH c, collect(e ) AS nodes +WHERE size(nodes) > 1 +CALL apoc.path.subgraphAll(nodes[0], { + whitelistNodes:nodes +}) +YIELD relationships +RETURN c.id AS communityId, + [n in nodes | {id: n.id, description: n.description, type: [el in labels(n) WHERE el <> '__Entity__'][0]}] AS nodes, + [r in relationships | {start: startNode(r).id, type: type(r), end: endNode(r).id, description: r.description}] AS rels +""" + +STORE_COMMUNITY_SUMMARIES = """ +UNWIND $data AS row +MERGE (c:__Community__ {id:row.community}) +SET c.summary = row.summary +""" + +COMMUNITY_TEMPLATE = """Based on the provided nodes and relationships that belong to the same graph community, +generate a natural language summary of the provided information: +{community_info} + +Summary:""" + + + +def get_gds_driver(uri, username, password, database): + try: + gds = GraphDataScience( + endpoint=uri, + auth=(username, password), + database=database + ) + logging.info("Successfully created GDS driver.") + return gds + except Exception as e: + logging.error(f"Failed to create GDS driver: {e}") + raise + +def create_community_graph_project(gds, project_name=COMMUNITY_PROJECT_NAME, node_projection=NODE_PROJECTION): + try: + existing_projects = gds.graph.list() + project_exists = existing_projects["graphName"].str.contains(project_name, regex=False).any() + + if project_exists: + logging.info(f"Project '{project_name}' already exists. Dropping it.") + gds.graph.drop(project_name) + + logging.info(f"Creating new graph project '{project_name}'.") + graph_project, result = gds.graph.project( + project_name, + node_projection, + { + "_ALL_": { + "type": "*", + "orientation": "UNDIRECTED", + "properties": { + "weight": { + "property": "*", + "aggregation": "COUNT" + } + } + } + } + ) + logging.info(f"Graph project '{project_name}' created successfully.") + return graph_project, result + except Exception as e: + logging.error(f"Failed to create community graph project: {e}") + raise + +def write_communities(gds, graph_project, project_name=COMMUNITY_PROJECT_NAME): + try: + logging.info(f"Writing communities to the graph project '{project_name}'.") + gds.leiden.write( + graph_project, + writeProperty=project_name, + includeIntermediateCommunities=True, + relationshipWeightProperty="weight" + ) + logging.info("Communities written successfully.") + return True + except Exception as e: + logging.error(f"Failed to write communities: {e}") + return False + + +def get_community_chain(model, community_template=COMMUNITY_TEMPLATE): + try: + llm, model_name = get_llm(model) + community_prompt = ChatPromptTemplate.from_messages( + [ + ( + "system", + "Given input triples, generate the information summary. No pre-amble.", + ), + ("human", community_template), + ] + ) + + community_chain = community_prompt | llm | StrOutputParser() + return community_chain + except Exception as e: + logging.error(f"Failed to create community chain: {e}") + raise + + +def prepare_string(community_data): + try: + nodes_description = "Nodes are:\n" + for node in community_data['nodes']: + node_id = node['id'] + node_type = node['type'] + node_description = f", description: {node['description']}" if 'description' in node and node['description'] else "" + nodes_description += f"id: {node_id}, type: {node_type}{node_description}\n" + + relationships_description = "Relationships are:\n" + for rel in community_data['rels']: + start_node = rel['start'] + end_node = rel['end'] + relationship_type = rel['type'] + relationship_description = f", description: {rel['description']}" if 'description' in rel and rel['description'] else "" + relationships_description += f"({start_node})-[:{relationship_type}]->({end_node}){relationship_description}\n" + + return nodes_description + "\n" + relationships_description + except Exception as e: + logging.error(f"Failed to prepare string from community data: {e}") + raise + +def process_community(community, community_chain): + try: + formatted_community_info = prepare_string(community) + summary = community_chain.invoke({'community_info': formatted_community_info}) + return {"community": community['communityId'], "summary": summary} + except Exception as e: + logging.error(f"Failed to process community {community.get('communityId', 'unknown')}: {e}") + raise + +def create_community_summaries(graph, model): + try: + community_info_list = graph.query(GET_COMMUNITY_INFO) + community_chain = get_community_chain(model) + + summaries = [] + with ThreadPoolExecutor() as executor: + futures = {executor.submit(process_community, community, community_chain): community for community in community_info_list} + + for future in tqdm(as_completed(futures), total=len(futures), desc="Processing communities"): + try: + summaries.append(future.result()) + except Exception as e: + logging.error(f"Failed to retrieve result for a community: {e}") + + graph.query(STORE_COMMUNITY_SUMMARIES, params={"data": summaries}) + except Exception as e: + logging.error(f"Failed to create community summaries: {e}") + raise + + +def create_community_properties(graph, model): + try: + # Create community levels + graph.query(CREATE_COMMUNITY_LEVELS) + logging.info("Successfully created community levels.") + + # Create community ranks + graph.query(CREATE_COMMUNITY_RANKS) + logging.info("Successfully created community ranks.") + + # Create community weights + graph.query(CREATE_COMMUNITY_WEIGHTS) + logging.info("Successfully created community weights.") + + # Create community summaries + create_community_summaries(graph, model) + logging.info("Successfully created community summaries.") + except Exception as e: + logging.error(f"Failed to create community properties: {e}") + raise + +def create_communities(uri, username, password, database,graph,model): + try: + gds = get_gds_driver(uri, username, password, database) + graph_project, result = create_community_graph_project(gds) + write_communities_sucess = write_communities(gds, graph_project) + if write_communities_sucess: + logging.info("Applying community constraint to the graph.") + graph.query(CREATE_COMMUNITY_CONSTRAINT) + create_community_properties(graph,model) + logging.info("Communities creation process completed successfully.") + else: + logging.warning("Failed to write communities. Constraint was not applied.") + except Exception as e: + logging.error(f"Failed to create communities: {e}") + + + + + + diff --git a/backend/src/create_communities.py b/backend/src/create_communities.py deleted file mode 100644 index 816dc9765..000000000 --- a/backend/src/create_communities.py +++ /dev/null @@ -1,132 +0,0 @@ -import os -from langchain_community.graphs import Neo4jGraph -from graphdatascience import GraphDataScience -import pandas as pd -import numpy as np -from langchain_core.prompts import ChatPromptTemplate -from langchain_core.output_parsers import StrOutputParser -from src.llm import get_llm - -import os -import getpass -from neo4j import GraphDatabase, Result -import pandas as pd -import seaborn as sns -import matplotlib.pyplot as plt -import tiktoken -import numpy as np -from langchain_openai import OpenAIEmbeddings, ChatOpenAI -from langchain_community.vectorstores import Neo4jVector -from langchain_community.graphs import Neo4jGraph -from langchain_core.prompts import ChatPromptTemplate -from langchain_core.output_parsers import StrOutputParser - -from tqdm import tqdm -from src.shared.common_fn import load_embedding_model - - -from typing import Dict, Any -from concurrent.futures import ThreadPoolExecutor, as_completed -from tqdm import tqdm -from src.llm import get_llm - -import logging -from graphdatascience import GraphDataScience - -COMMUNITY_PROJECT_NAME = "communities" -NODE_PROJECTION = "__Entity__" -CREATE_COMMUNITY_CONSTRAINT = "CREATE CONSTRAINT IF NOT EXISTS FOR (c:__Community__) REQUIRE c.id IS UNIQUE;" - -def get_gds_driver(uri, username, password, database): - try: - gds = GraphDataScience( - endpoint=uri, - auth=(username, password), - database=database - ) - logging.info("Successfully created GDS driver.") - return gds - except Exception as e: - logging.error(f"Failed to create GDS driver: {e}") - raise - -def create_community_graph_project(gds, project_name=COMMUNITY_PROJECT_NAME, node_projection=NODE_PROJECTION): - try: - existing_projects = gds.graph.list() - project_exists = existing_projects["graphName"].str.contains(project_name, regex=False).any() - - if project_exists: - logging.info(f"Project '{project_name}' already exists. Dropping it.") - gds.graph.drop(project_name) - - logging.info(f"Creating new graph project '{project_name}'.") - graph_project, result = gds.graph.project( - project_name, - node_projection, - { - "_ALL_": { - "type": "*", - "orientation": "UNDIRECTED", - "properties": { - "weight": { - "property": "*", - "aggregation": "COUNT" - } - } - } - } - ) - logging.info(f"Graph project '{project_name}' created successfully.") - return graph_project, result - except Exception as e: - logging.error(f"Failed to create community graph project: {e}") - raise - -def write_communities(gds, graph_project, project_name=COMMUNITY_PROJECT_NAME): - try: - logging.info(f"Writing communities to the graph project '{project_name}'.") - gds.leiden.write( - graph_project, - writeProperty=project_name, - includeIntermediateCommunities=True, - relationshipWeightProperty="weight" - ) - logging.info("Communities written successfully.") - return True - except Exception as e: - logging.error(f"Failed to write communities: {e}") - return False - - - - -def create_communities(uri, username, password, database,graph): - try: - gds = get_gds_driver(uri, username, password, database) - graph_project, result = create_community_graph_project(gds) - - if write_communities(gds, graph_project): - logging.info("Applying community constraint to the graph.") - graph.query(CREATE_COMMUNITY_CONSTRAINT) - # Optionally, you can call create_community_properties() here if needed - logging.info("Communities creation process completed successfully.") - else: - logging.warning("Failed to write communities. Constraint was not applied.") - except Exception as e: - logging.error(f"Failed to create communities: {e}") - - - -# def create_communities(uri,username,password,database,graph): -# gds = get_gds_driver(uri,username,password,database) -# graph_project,result = create_community_graph_project(gds) -# result1 = write_communities(gds,graph_project) -# if result1: -# graph.query(CREATE_COMMUNITY_CONSTRAINT) -# # create_community_properties() - - - - - - diff --git a/experiments/graphrag.ipynb b/experiments/graphrag.ipynb new file mode 100644 index 000000000..a3f99796a --- /dev/null +++ b/experiments/graphrag.ipynb @@ -0,0 +1,3519 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# !pip install --quiet --upgrade langchain-community langchain-experimental langchain-openai neo4j graphdatascience tiktoken retry" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/workspaces/llm-graph-builder/chatbotenv/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", + " from .autonotebook import tqdm as notebook_tqdm\n" + ] + } + ], + "source": [ + "import getpass\n", + "import os\n", + "from langchain_community.graphs import Neo4jGraph\n", + "from graphdatascience import GraphDataScience\n", + "import pandas as pd\n", + "import numpy as np\n", + "from langchain_core.prompts import ChatPromptTemplate\n", + "from langchain_core.output_parsers import StrOutputParser\n", + "from src.llm import get_llm\n", + "\n", + "import os\n", + "import getpass\n", + "from neo4j import GraphDatabase, Result\n", + "import pandas as pd\n", + "import seaborn as sns\n", + "import matplotlib.pyplot as plt\n", + "import tiktoken\n", + "import numpy as np\n", + "from langchain_openai import OpenAIEmbeddings, ChatOpenAI\n", + "from langchain_community.vectorstores import Neo4jVector\n", + "from langchain_community.graphs import Neo4jGraph\n", + "from langchain_core.prompts import ChatPromptTemplate\n", + "from langchain_core.output_parsers import StrOutputParser\n", + "# from llama_index.core.schema import TextNode\n", + "# from llama_index.core.vector_stores.utils import node_to_metadata_dict\n", + "# from llama_index.vector_stores.neo4jvector import Neo4jVectorStore\n", + "# from llama_index.core import VectorStoreIndex\n", + "from tqdm import tqdm\n", + "from src.shared.common_fn import load_embedding_model\n", + "\n", + "\n", + "from typing import Dict, Any\n", + "from concurrent.futures import ThreadPoolExecutor, as_completed\n", + "from tqdm import tqdm\n", + "from src.llm import get_llm" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "os.environ[\"NEO4J_URI\"] = \"\"\n", + "os.environ[\"NEO4J_USERNAME\"] = \"neo4j\"\n", + "os.environ[\"NEO4J_PASSWORD\"] = \"\"\n", + "os.environ[\"OPENAI_API_KEY\"] = \"\"" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Received notification from DBMS server: {severity: WARNING} {code: Neo.ClientNotification.Statement.FeatureDeprecationWarning} {category: DEPRECATION} {title: This feature is deprecated and will be removed in future versions.} {description: The query used a deprecated field from a procedure. ('advertisedListenAddress' returned by 'gds.debug.arrow' is deprecated.)} {position: line: 1, column: 1, offset: 0} for query: 'CALL gds.debug.arrow()'\n", + "Received notification from DBMS server: {severity: WARNING} {code: Neo.ClientNotification.Statement.FeatureDeprecationWarning} {category: DEPRECATION} {title: This feature is deprecated and will be removed in future versions.} {description: The query used a deprecated field from a procedure. ('serverLocation' returned by 'gds.debug.arrow' is deprecated.)} {position: line: 1, column: 1, offset: 0} for query: 'CALL gds.debug.arrow()'\n" + ] + } + ], + "source": [ + "gds = GraphDataScience(\n", + " os.environ[\"NEO4J_URI\"],\n", + " auth=(os.environ[\"NEO4J_USERNAME\"], os.environ[\"NEO4J_PASSWORD\"])\n", + ")\n", + "\n", + "graph = Neo4jGraph() \n", + "\n", + "driver = GraphDatabase.driver(os.environ[\"NEO4J_URI\"], auth=(os.environ[\"NEO4J_USERNAME\"], os.environ[\"NEO4J_PASSWORD\"]))" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'type': 'node', 'total_count': 185, 'non_null_descriptions': 146},\n", + " {'type': 'relationship', 'total_count': 14614, 'non_null_descriptions': 41}]" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "graph.query(\"\"\"\n", + "MATCH (n:`__Entity__`)\n", + "RETURN \"node\" AS type,\n", + " count(*) AS total_count,\n", + " count(n.description) AS non_null_descriptions\n", + "UNION ALL\n", + "MATCH (n)-[r:!MENTIONS]->()\n", + "RETURN \"relationship\" AS type,\n", + " count(*) AS total_count,\n", + " count(r.description) AS non_null_descriptions\n", + "\"\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Received notification from DBMS server: {severity: WARNING} {code: Neo.ClientNotification.Statement.FeatureDeprecationWarning} {category: DEPRECATION} {title: This feature is deprecated and will be removed in future versions.} {description: The query used a deprecated field from a procedure. ('schema' returned by 'gds.graph.list' is deprecated.)} {position: line: 1, column: 1, offset: 0} for query: 'CALL gds.graph.list()'\n" + ] + } + ], + "source": [ + "available_graphs = gds.graph.list()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "available_graphs.drop([0,1],inplace=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
degreeDistributiongraphNamedatabasedatabaseLocationmemoryUsagesizeInBytesnodeCountrelationshipCountconfigurationdensitycreationTimemodificationTimeschemaschemaWithOrientation
\n", + "
" + ], + "text/plain": [ + "Empty DataFrame\n", + "Columns: [degreeDistribution, graphName, database, databaseLocation, memoryUsage, sizeInBytes, nodeCount, relationshipCount, configuration, density, creationTime, modificationTime, schema, schemaWithOrientation]\n", + "Index: []" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "available_graphs" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "available_graphs[\"graphName\"].str.contains('communities', regex=False).any()" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Received notification from DBMS server: {severity: WARNING} {code: Neo.ClientNotification.Statement.FeatureDeprecationWarning} {category: DEPRECATION} {title: This feature is deprecated and will be removed in future versions.} {description: The query used a deprecated field from a procedure. ('schema' returned by 'gds.graph.drop' is deprecated.)} {position: line: 1, column: 1, offset: 0} for query: 'CALL gds.graph.drop($graph_name, $fail_if_missing, $db_name)'\n" + ] + }, + { + "data": { + "text/plain": [ + "graphName communities\n", + "database neo4j\n", + "databaseLocation local\n", + "memoryUsage \n", + "sizeInBytes -1\n", + "nodeCount 185\n", + "relationshipCount 366\n", + "configuration {'relationshipProjection': {'_ALL_': {'aggrega...\n", + "density 0.010752\n", + "creationTime 2024-08-19T12:41:43.997435629+00:00\n", + "modificationTime 2024-08-19T12:41:44.127124307+00:00\n", + "schema {'graphProperties': {}, 'nodes': {'__Entity__'...\n", + "schemaWithOrientation {'graphProperties': {}, 'nodes': {'__Entity__'...\n", + "Name: 0, dtype: object" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gds.graph.drop(\"communities\")" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "G, result = gds.graph.project(\n", + " \"communities\", # Graph name\n", + " \"__Entity__\", # Node projection\n", + " {\n", + " \"_ALL_\": {\n", + " \"type\": \"*\",\n", + " \"orientation\": \"UNDIRECTED\",\n", + " \"properties\": {\"weight\": {\"property\": \"*\", \"aggregation\": \"COUNT\"}},\n", + " }\n", + " },\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "nodeProjection {'__Entity__': {'label': '__Entity__', 'proper...\n", + "relationshipProjection {'_ALL_': {'aggregation': 'DEFAULT', 'orientat...\n", + "graphName communities\n", + "nodeCount 185\n", + "relationshipCount 366\n", + "projectMillis 15\n", + "Name: 0, dtype: object" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "result" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Received notification from DBMS server: {severity: WARNING} {code: Neo.ClientNotification.Statement.FeatureDeprecationWarning} {category: DEPRECATION} {title: This feature is deprecated and will be removed in future versions.} {description: The query used a deprecated field from a procedure. ('schema' returned by 'gds.graph.list' is deprecated.)} {position: line: 1, column: 106, offset: 105} for query: 'CALL gds.graph.list($graph_name) YIELD graphName, nodeCount, relationshipCount, database, configuration, schema, memoryUsage'\n" + ] + }, + { + "data": { + "text/plain": [ + "Graph({'graphName': 'communities', 'nodeCount': 185, 'relationshipCount': 366, 'database': 'neo4j', 'configuration': {'relationshipProjection': {'_ALL_': {'aggregation': 'DEFAULT', 'orientation': 'UNDIRECTED', 'indexInverse': False, 'properties': {'weight': {'aggregation': 'COUNT', 'property': '*', 'defaultValue': None}}, 'type': '*'}}, 'readConcurrency': 4, 'relationshipProperties': {}, 'nodeProperties': {}, 'jobId': 'ced0b057-a717-48d8-8b90-842f6f2aa001', 'nodeProjection': {'__Entity__': {'label': '__Entity__', 'properties': {}}}, 'logProgress': True, 'creationTime': neo4j.time.DateTime(2024, 8, 19, 13, 10, 3, 641071700, tzinfo=), 'validateRelationships': False, 'sudo': False}, 'schema': {'graphProperties': {}, 'nodes': {'__Entity__': {}}, 'relationships': {'_ALL_': {'weight': 'Float (DefaultValue(NaN), PERSISTENT, Aggregation.COUNT)'}}}, 'memoryUsage': '2316 KiB'})" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "G" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'COMMUNITY_PROJECT_NAME'" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\"community_project_name\".upper()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Component count: 14\n", + "Component distribution: {'min': 1, 'p5': 1, 'max': 155, 'p999': 155, 'p99': 155, 'p1': 1, 'p10': 1, 'p90': 3, 'p50': 1, 'p25': 1, 'p75': 2, 'p95': 155, 'mean': 12.285714285714286}\n" + ] + } + ], + "source": [ + "wcc = gds.wcc.stats(G)\n", + "print(f\"Component count: {wcc['componentCount']}\")\n", + "print(f\"Component distribution: {wcc['componentDistribution']}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "writeMillis 5\n", + "nodePropertiesWritten 172\n", + "ranLevels 2\n", + "didConverge True\n", + "nodeCount 172\n", + "communityCount 22\n", + "communityDistribution {'min': 1, 'p5': 1, 'max': 64, 'p999': 64, 'p9...\n", + "modularity 0.678705\n", + "modularities [0.6566821889989846, 0.6787052274080039]\n", + "postProcessingMillis 3\n", + "preProcessingMillis 0\n", + "computeMillis 33\n", + "configuration {'writeProperty': 'communities', 'theta': 0.01...\n", + "Name: 0, dtype: object" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gds.leiden.write(\n", + " G,\n", + " writeProperty=\"communities\",\n", + " includeIntermediateCommunities=True,\n", + " relationshipWeightProperty=\"weight\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "graph.query(\"CREATE CONSTRAINT IF NOT EXISTS FOR (c:__Community__) REQUIRE c.id IS UNIQUE;\")" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'count(*)': 344}]" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "graph.query(\"\"\"\n", + "MATCH (e:`__Entity__`)\n", + "UNWIND range(0, size(e.communities) - 1 , 1) AS index\n", + "CALL {\n", + " WITH e, index\n", + " WITH e, index\n", + " WHERE index = 0\n", + " MERGE (c:`__Community__` {id: toString(index) + '-' + toString(e.communities[index])})\n", + " ON CREATE SET c.level = index\n", + " MERGE (e)-[:IN_COMMUNITY]->(c)\n", + " RETURN count(*) AS count_0\n", + "}\n", + "CALL {\n", + " WITH e, index\n", + " WITH e, index\n", + " WHERE index > 0\n", + " MERGE (current:`__Community__` {id: toString(index) + '-' + toString(e.communities[index])})\n", + " ON CREATE SET current.level = index\n", + " MERGE (previous:`__Community__` {id: toString(index - 1) + '-' + toString(e.communities[index - 1])})\n", + " ON CREATE SET previous.level = index - 1\n", + " MERGE (previous)-[:IN_COMMUNITY]->(current)\n", + " RETURN count(*) AS count_1\n", + "}\n", + "RETURN count(*)\n", + "\"\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "graph.query(\"\"\"\n", + "MATCH (c:__Community__)<-[:IN_COMMUNITY*]-(:__Entity__)<-[:MENTIONS]-(d:Document)\n", + "WITH c, count(distinct d) AS rank\n", + "SET c.community_rank = rank;\n", + "\"\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
LevelNumber of communities25th Percentile50th Percentile75th Percentile90th Percentile99th PercentileMax
00281.02.03.7513.949.6661
11221.02.08.5017.854.5564
\n", + "
" + ], + "text/plain": [ + " Level Number of communities 25th Percentile 50th Percentile \\\n", + "0 0 28 1.0 2.0 \n", + "1 1 22 1.0 2.0 \n", + "\n", + " 75th Percentile 90th Percentile 99th Percentile Max \n", + "0 3.75 13.9 49.66 61 \n", + "1 8.50 17.8 54.55 64 " + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\n", + "community_size = graph.query(\n", + " \"\"\"\n", + "MATCH (c:__Community__)<-[:IN_COMMUNITY*]-(e:__Entity__)\n", + "WITH c, count(distinct e) AS entities\n", + "RETURN split(c.id, '-')[0] AS level, entities\n", + "\"\"\"\n", + ")\n", + "community_size_df = pd.DataFrame.from_records(community_size)\n", + "percentiles_data = []\n", + "for level in community_size_df[\"level\"].unique():\n", + " subset = community_size_df[community_size_df[\"level\"] == level][\"entities\"]\n", + " num_communities = len(subset)\n", + " percentiles = np.percentile(subset, [25, 50, 75, 90, 99])\n", + " percentiles_data.append(\n", + " [\n", + " level,\n", + " num_communities,\n", + " percentiles[0],\n", + " percentiles[1],\n", + " percentiles[2],\n", + " percentiles[3],\n", + " percentiles[4],\n", + " max(subset)\n", + " ]\n", + " )\n", + "\n", + "# Create a DataFrame with the percentiles\n", + "percentiles_df = pd.DataFrame(\n", + " percentiles_data,\n", + " columns=[\n", + " \"Level\",\n", + " \"Number of communities\",\n", + " \"25th Percentile\",\n", + " \"50th Percentile\",\n", + " \"75th Percentile\",\n", + " \"90th Percentile\",\n", + " \"99th Percentile\",\n", + " \"Max\"\n", + " ],\n", + ")\n", + "percentiles_df\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### community summaries" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "community_info = graph.query(\"\"\"\n", + "MATCH (c:`__Community__`)<-[:IN_COMMUNITY*]-(e:__Entity__)\n", + "WHERE c.level IN [0,1,4]\n", + "WITH c, collect(e ) AS nodes\n", + "WHERE size(nodes) > 1\n", + "CALL apoc.path.subgraphAll(nodes[0], {\n", + "\twhitelistNodes:nodes\n", + "})\n", + "YIELD relationships\n", + "RETURN c.id AS communityId,\n", + " [n in nodes | {id: n.id, description: n.description, type: [el in labels(n) WHERE el <> '__Entity__'][0]}] AS nodes,\n", + " [r in relationships | {start: startNode(r).id, type: type(r), end: endNode(r).id, description: r.description}] AS rels\n", + "\"\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'communityId': '0-36',\n", + " 'nodes': [{'id': 'India',\n", + " 'description': 'Officially the Republic of India, located in South Asia.',\n", + " 'type': 'Country'},\n", + " {'id': 'Supreme Court Of India',\n", + " 'description': 'Head of the independent judiciary.',\n", + " 'type': 'Judiciary'},\n", + " {'id': 'Indian National Congress',\n", + " 'description': 'Dominated Indian politics until 1977.',\n", + " 'type': 'Political party'},\n", + " {'id': 'Sindhu',\n", + " 'description': 'Name of the Indus River, from which the name India is derived.',\n", + " 'type': 'River'},\n", + " {'id': 'Food And Agriculture Organization Of The United Nations',\n", + " 'description': \"Estimates India's forest cover.\",\n", + " 'type': 'Organization'},\n", + " {'id': '2013 Forest Survey Of India',\n", + " 'description': \"States India's forest cover increased to 69.8 million hectares by 2012.\",\n", + " 'type': 'Report'},\n", + " {'id': 'Yajnavalkya Smriti',\n", + " 'description': 'Prohibited the cutting of trees.',\n", + " 'type': 'Literature'},\n", + " {'id': 'Kautalyas Arthashastra',\n", + " 'description': 'Discusses the need for forest administration.',\n", + " 'type': 'Literature'},\n", + " {'id': 'Crown Land (Encroachment) Ordinance',\n", + " 'description': \"Promulgated in 1840 targeting forests in Britain's Asian colonies.\",\n", + " 'type': 'Legislation'},\n", + " {'id': 'Indian Forest Act Of 1865',\n", + " 'description': \"Established the government's claims over forests.\",\n", + " 'type': 'Legislation'},\n", + " {'id': 'Forest Act Of 1878',\n", + " 'description': 'Gave the British government control over all wastelands, including forests.',\n", + " 'type': 'Legislation'},\n", + " {'id': 'Sir Dietrich Brandis',\n", + " 'description': 'Inspector General of Forests in India from 1864 to 1883.',\n", + " 'type': 'Person'},\n", + " {'id': 'Indian Ocean',\n", + " 'description': 'Ocean bounded by India on the north.',\n", + " 'type': 'Ocean'},\n", + " {'id': 'Sri Lanka',\n", + " 'description': 'Country in the vicinity of India in the Indian Ocean.',\n", + " 'type': 'Country'},\n", + " {'id': 'Maldives',\n", + " 'description': 'Country in the vicinity of India in the Indian Ocean.',\n", + " 'type': 'Country'},\n", + " {'id': 'Myanmar',\n", + " 'description': 'Country sharing land border with India to the east.',\n", + " 'type': 'Country'},\n", + " {'id': 'Himalayan Mountain Range',\n", + " 'description': 'Defines the northern frontiers of India.',\n", + " 'type': 'Mountain range'},\n", + " {'id': 'China',\n", + " 'description': 'Country sharing land border with India to the north.',\n", + " 'type': 'Country'},\n", + " {'id': 'Bhutan',\n", + " 'description': 'Country sharing land border with India to the north.',\n", + " 'type': 'Country'},\n", + " {'id': 'Nepal',\n", + " 'description': 'Country sharing land border with India to the north.',\n", + " 'type': 'Country'},\n", + " {'id': 'Pakistan',\n", + " 'description': 'Country sharing land border with India to the west.',\n", + " 'type': 'Country'},\n", + " {'id': 'Bangladesh',\n", + " 'description': 'Country sharing land border with India to the east.',\n", + " 'type': 'Country'},\n", + " {'id': 'Ganges',\n", + " 'description': 'The longest river originating in India.',\n", + " 'type': 'River'},\n", + " {'id': 'Western Ghats',\n", + " 'description': 'One of the three biodiversity hotspots in India.',\n", + " 'type': 'Biodiversity hotspot'},\n", + " {'id': 'Eastern Himalayas',\n", + " 'description': 'One of the three biodiversity hotspots in India.',\n", + " 'type': 'Biodiversity hotspot'},\n", + " {'id': 'Indo-Burma Hotspot',\n", + " 'description': 'One of the three biodiversity hotspots in India.',\n", + " 'type': 'Biodiversity hotspot'},\n", + " {'id': 'Forests',\n", + " 'description': 'Covers about 24.6% of the total land area.',\n", + " 'type': 'Ecosystem'},\n", + " {'id': 'Indomalayan Realm',\n", + " 'description': 'Geographical realm that includes India.',\n", + " 'type': 'Realm'},\n", + " {'id': 'World', 'description': None, 'type': None},\n", + " {'id': 'Public_Sector', 'description': None, 'type': None},\n", + " {'id': 'Gdp', 'description': None, 'type': None},\n", + " {'id': 'Economic_Liberalisation', 'description': None, 'type': None},\n", + " {'id': 'Gdp_Growth', 'description': None, 'type': None},\n", + " {'id': 'Consumer_Market', 'description': None, 'type': None},\n", + " {'id': 'Wto', 'description': None, 'type': None},\n", + " {'id': 'Ease_Of_Business_Index', 'description': None, 'type': None},\n", + " {'id': 'Global_Competitiveness_Index', 'description': None, 'type': None},\n", + " {'id': 'Billionaires', 'description': None, 'type': None},\n", + " {'id': 'Welfare_State', 'description': None, 'type': None},\n", + " {'id': 'Socialist_State', 'description': None, 'type': None},\n", + " {'id': 'Social_Welfare_Spending', 'description': None, 'type': None},\n", + " {'id': 'Labour_Force', 'description': None, 'type': None},\n", + " {'id': 'Fdi', 'description': None, 'type': None},\n", + " {'id': 'Free_Trade_Agreements', 'description': None, 'type': None},\n", + " {'id': 'Service_Sector', 'description': None, 'type': None},\n", + " {'id': 'Stock_Exchanges', 'description': None, 'type': None},\n", + " {'id': 'Manufacturing', 'description': None, 'type': None},\n", + " {'id': 'Population', 'description': None, 'type': None},\n", + " {'id': 'Unemployment', 'description': None, 'type': None},\n", + " {'id': 'Savings_Rate', 'description': None, 'type': None},\n", + " {'id': 'Arabian Sea',\n", + " 'description': 'Sea bounded by India on the northwest.',\n", + " 'type': 'Sea'},\n", + " {'id': 'Bay Of Bengal',\n", + " 'description': 'Bay bounded by India on the southeast.',\n", + " 'type': 'Bay'},\n", + " {'id': 'Africa',\n", + " 'description': 'Continent from which modern humans arrived on the Indian subcontinent.',\n", + " 'type': 'Continent'},\n", + " {'id': 'Indus Valley Civilisation',\n", + " 'description': 'Civilisation that evolved from settled life in the western margins of the Indus river basin.',\n", + " 'type': 'Civilization'},\n", + " {'id': 'Sanskrit',\n", + " 'description': 'Indo-European language that diffused into India from the northwest.',\n", + " 'type': 'Language'},\n", + " {'id': 'Rigveda',\n", + " 'description': 'Ancient hymns recording the dawning of Hinduism in India.',\n", + " 'type': 'Text'},\n", + " {'id': 'Hinduism',\n", + " 'description': 'Major religion in India, with roots in the Rigveda.',\n", + " 'type': 'Religion'},\n", + " {'id': 'Buddhism',\n", + " 'description': 'Religion that arose in India, proclaiming social orders unlinked to heredity.',\n", + " 'type': 'Religion'},\n", + " {'id': 'Jainism',\n", + " 'description': 'Religion that arose in India, proclaiming social orders unlinked to heredity.',\n", + " 'type': 'Religion'},\n", + " {'id': 'Mughal Empire',\n", + " 'description': 'Empire that began in 1526, known for its architecture and relative peace.',\n", + " 'type': 'Empire'},\n", + " {'id': 'Indian Republic',\n", + " 'description': 'India has been a federal republic since 1950.',\n", + " 'type': 'Government'}],\n", + " 'rels': [{'start': 'India',\n", + " 'description': None,\n", + " 'type': 'IS_PART_OF',\n", + " 'end': 'Indomalayan Realm'},\n", + " {'start': 'India',\n", + " 'description': 'About 1,900 public sector companies with complete control and ownership of railways, highways, and majority control in various industries.',\n", + " 'type': 'HAS',\n", + " 'end': 'Public_Sector'},\n", + " {'start': 'India',\n", + " 'description': \"One of the world's highest number of billionaires.\",\n", + " 'type': 'HAS',\n", + " 'end': 'Billionaires'},\n", + " {'start': 'India',\n", + " 'description': \"World's second-largest labour force with 586 million workers.\",\n", + " 'type': 'HAS',\n", + " 'end': 'Labour_Force'},\n", + " {'start': 'India',\n", + " 'description': 'Has free trade agreements with several nations and blocs.',\n", + " 'type': 'HAS',\n", + " 'end': 'Free_Trade_Agreements'},\n", + " {'start': 'India',\n", + " 'description': \"Bombay Stock Exchange and National Stock Exchange are among the world's largest stock exchanges.\",\n", + " 'type': 'HAS',\n", + " 'end': 'Stock_Exchanges'},\n", + " {'start': 'India',\n", + " 'description': \"Nearly 65% of India's population is rural.\",\n", + " 'type': 'HAS',\n", + " 'end': 'Population'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'RELATES_TO',\n", + " 'end': 'Rigveda'},\n", + " {'start': 'India',\n", + " 'description': 'Member of the World Trade Organization since 1 January 1995.',\n", + " 'type': 'MEMBER_OF',\n", + " 'end': 'Wto'},\n", + " {'start': 'India',\n", + " 'description': 'High unemployment and rising income inequality.',\n", + " 'type': 'FACES',\n", + " 'end': 'Unemployment'},\n", + " {'start': 'India',\n", + " 'description': 'Adopted broad economic liberalisation in 1991.',\n", + " 'type': 'ADOPTED',\n", + " 'end': 'Economic_Liberalisation'},\n", + " {'start': 'India',\n", + " 'description': 'Often considered a welfare state.',\n", + " 'type': 'CONSIDERED_AS',\n", + " 'end': 'Welfare_State'},\n", + " {'start': 'India', 'description': None, 'type': 'NEAR', 'end': 'Sri Lanka'},\n", + " {'start': 'India', 'description': None, 'type': 'NEAR', 'end': 'Maldives'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'BORDERS',\n", + " 'end': 'Indian Ocean'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'BORDERS',\n", + " 'end': 'Myanmar'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'BORDERS',\n", + " 'end': 'Himalayan Mountain Range'},\n", + " {'start': 'India', 'description': None, 'type': 'BORDERS', 'end': 'China'},\n", + " {'start': 'India', 'description': None, 'type': 'BORDERS', 'end': 'Bhutan'},\n", + " {'start': 'India', 'description': None, 'type': 'BORDERS', 'end': 'Nepal'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'BORDERS',\n", + " 'end': 'Pakistan'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'BORDERS',\n", + " 'end': 'Bangladesh'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'BORDERS',\n", + " 'end': 'Arabian Sea'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'BORDERS',\n", + " 'end': 'Bay Of Bengal'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'SEPARATED_BY',\n", + " 'end': 'Sri Lanka'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'DERIVED_FROM',\n", + " 'end': 'Sindhu'},\n", + " {'start': 'India',\n", + " 'description': \"Estimates India's forest cover.\",\n", + " 'type': 'ESTIMATES',\n", + " 'end': 'Food And Agriculture Organization Of The United Nations'},\n", + " {'start': 'India',\n", + " 'description': 'Makes up more than 50% of GDP.',\n", + " 'type': 'MAKES_UP',\n", + " 'end': 'Service_Sector'},\n", + " {'start': 'India',\n", + " 'description': 'Fifth-largest economy by nominal GDP and third-largest by purchasing power parity (PPP).',\n", + " 'type': 'RANKS_AS',\n", + " 'end': 'World'},\n", + " {'start': 'India',\n", + " 'description': 'Fourth-largest consumer market in the world.',\n", + " 'type': 'RANKS_AS',\n", + " 'end': 'Consumer_Market'},\n", + " {'start': 'India',\n", + " 'description': \"World's sixth-largest manufacturer, representing 2.6% of global manufacturing output.\",\n", + " 'type': 'RANKS_AS',\n", + " 'end': 'Manufacturing'},\n", + " {'start': 'India',\n", + " 'description': 'Officially declared a socialist state as per the constitution.',\n", + " 'type': 'DECLARED_AS',\n", + " 'end': 'Socialist_State'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'ORIGIN_OF',\n", + " 'end': 'Hinduism'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'ORIGIN_OF',\n", + " 'end': 'Buddhism'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'ORIGIN_OF',\n", + " 'end': 'Jainism'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'GOVERNED_AS',\n", + " 'end': 'Indian Republic'},\n", + " {'start': 'India',\n", + " 'description': '136th by GDP (nominal) and 125th by GDP (PPP) on a per capita income basis.',\n", + " 'type': 'RANKS',\n", + " 'end': 'Gdp'},\n", + " {'start': 'India',\n", + " 'description': '63rd on the Ease of Doing Business index.',\n", + " 'type': 'RANKS',\n", + " 'end': 'Ease_Of_Business_Index'},\n", + " {'start': 'India',\n", + " 'description': '40th on the Global Competitiveness Index.',\n", + " 'type': 'RANKS',\n", + " 'end': 'Global_Competitiveness_Index'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'SHARES_BORDERS_WITH',\n", + " 'end': 'Myanmar'},\n", + " {'start': 'India',\n", + " 'description': 'Overall social welfare spending stood at 8.6% of GDP in 2021-22.',\n", + " 'type': 'SPENDING',\n", + " 'end': 'Social_Welfare_Spending'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'HISTORICAL_EVENT',\n", + " 'end': 'Mughal Empire'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'ORIGINATES_IN',\n", + " 'end': 'Ganges'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'HAS_BIODIVERSITY_HOTSPOT',\n", + " 'end': 'Western Ghats'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'HAS_BIODIVERSITY_HOTSPOT',\n", + " 'end': 'Eastern Himalayas'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'HAS_BIODIVERSITY_HOTSPOT',\n", + " 'end': 'Indo-Burma Hotspot'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'HAS_ECOSYSTEM',\n", + " 'end': 'Forests'},\n", + " {'start': 'India',\n", + " 'description': '6% to 7% since the start of the 21st century.',\n", + " 'type': 'AVERAGE_ANNUAL_GROWTH',\n", + " 'end': 'Gdp_Growth'},\n", + " {'start': 'India',\n", + " 'description': 'Foreign direct investment in 2021-22 was $82 billion.',\n", + " 'type': 'FOREIGN_DIRECT_INVESTMENT',\n", + " 'end': 'Fdi'},\n", + " {'start': 'India',\n", + " 'description': 'Gross domestic savings rate stood at 29.3% of GDP in 2022.',\n", + " 'type': 'GROSS_DOMESTIC_SAVINGS_RATE',\n", + " 'end': 'Savings_Rate'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'HUMAN_ORIGIN',\n", + " 'end': 'Africa'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'HISTORICAL_DEVELOPMENT',\n", + " 'end': 'Indus Valley Civilisation'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'LANGUAGE_DIFFUSION',\n", + " 'end': 'Sanskrit'},\n", + " {'start': 'Kautalyas Arthashastra',\n", + " 'description': 'Discusses the need for forest administration.',\n", + " 'type': 'DISCUSSES',\n", + " 'end': 'India'},\n", + " {'start': 'Indian Forest Act Of 1865',\n", + " 'description': \"Establishes government's claims over forests.\",\n", + " 'type': 'ESTABLISHES',\n", + " 'end': 'India'},\n", + " {'start': 'Crown Land (Encroachment) Ordinance',\n", + " 'description': \"Targets forests in Britain's Asian colonies.\",\n", + " 'type': 'TARGETS',\n", + " 'end': 'India'},\n", + " {'start': 'Yajnavalkya Smriti',\n", + " 'description': 'Prohibits the cutting of trees.',\n", + " 'type': 'PROHIBITS',\n", + " 'end': 'India'},\n", + " {'start': '2013 Forest Survey Of India',\n", + " 'description': 'Reports on forest cover increase.',\n", + " 'type': 'REPORTS_ON',\n", + " 'end': 'India'},\n", + " {'start': 'Supreme Court Of India',\n", + " 'description': None,\n", + " 'type': 'PART_OF_JUDICIARY',\n", + " 'end': 'India'},\n", + " {'start': 'Indian National Congress',\n", + " 'description': None,\n", + " 'type': 'HISTORICALLY_DOMINANT_PARTY',\n", + " 'end': 'India'},\n", + " {'start': 'Forest Act Of 1878',\n", + " 'description': 'Gives control over all wastelands, including forests.',\n", + " 'type': 'GIVES_CONTROL',\n", + " 'end': 'India'},\n", + " {'start': 'Sir Dietrich Brandis',\n", + " 'description': 'Inspector General of Forests in India from 1864 to 1883.',\n", + " 'type': 'INSPECTOR_GENERAL_OF',\n", + " 'end': 'India'}]},\n", + " {'communityId': '0-34',\n", + " 'nodes': [{'id': 'Constitution Of India',\n", + " 'description': 'The supreme law of India, laying down the framework for government institutions and fundamental rights.',\n", + " 'type': 'Document'},\n", + " {'id': 'Parliament',\n", + " 'description': 'Cannot override the Constitution of India.',\n", + " 'type': 'Institution'},\n", + " {'id': 'Government Of India Act 1935',\n", + " 'description': 'Replaced by the Constitution of India.',\n", + " 'type': 'Document'},\n", + " {'id': 'Constituent Assembly',\n", + " 'description': 'Tasked with drafting the Constitution of India.',\n", + " 'type': 'Government body'},\n", + " {'id': 'M. N. Roy',\n", + " 'description': 'Proposed the framework for the Constitution of India.',\n", + " 'type': 'Person'},\n", + " {'id': 'Republic Day',\n", + " 'description': 'Celebrated on 26 January in India to honor the Constitution.',\n", + " 'type': 'Event'},\n", + " {'id': 'Old Parliament House',\n", + " 'description': 'Preserves the original 1950 Constitution in a nitrogen-filled case.',\n", + " 'type': 'Location'},\n", + " {'id': 'British Government',\n", + " 'description': 'Responsible for the external security of India during its dominion status.',\n", + " 'type': 'Institution'},\n", + " {'id': 'Indian Independence Act 1947',\n", + " 'description': 'Repealed by the Constitution of India.',\n", + " 'type': 'Document'},\n", + " {'id': 'Articles Of The Constitution',\n", + " 'description': 'Articles 5, 6, 7, 8, 9, 60, 324, 366, 367, 379, 380, 388, 391, 392, 393, and 394 came into force on 26 November 1949.',\n", + " 'type': 'Document'}],\n", + " 'rels': [{'start': 'Constitution Of India',\n", + " 'description': 'The Constitution is based on the proposal suggested by M. N. Roy.',\n", + " 'type': 'BASED_ON',\n", + " 'end': 'M. N. Roy'},\n", + " {'start': 'Constitution Of India',\n", + " 'description': 'The original 1950 Constitution is preserved in a nitrogen-filled case.',\n", + " 'type': 'PRESERVED_IN',\n", + " 'end': 'Old Parliament House'},\n", + " {'start': 'Constitution Of India',\n", + " 'description': 'Celebrated on 26 January.',\n", + " 'type': 'CELEBRATED_ON',\n", + " 'end': 'Republic Day'},\n", + " {'start': 'Constitution Of India',\n", + " 'description': 'Parliament cannot override the Constitution.',\n", + " 'type': 'CANNOT_OVERRIDE',\n", + " 'end': 'Parliament'},\n", + " {'start': 'Constitution Of India',\n", + " 'description': 'Certain articles came into force on 26 November 1949.',\n", + " 'type': 'CAME_INTO_FORCE',\n", + " 'end': 'Articles Of The Constitution'},\n", + " {'start': 'Government Of India Act 1935',\n", + " 'description': 'Replaced by the Constitution of India.',\n", + " 'type': 'REPLACED_BY',\n", + " 'end': 'Constitution Of India'},\n", + " {'start': 'British Government',\n", + " 'description': 'Responsible for the external security of India during its dominion status.',\n", + " 'type': 'RESPONSIBLE_FOR',\n", + " 'end': 'Constitution Of India'},\n", + " {'start': 'Indian Independence Act 1947',\n", + " 'description': 'Repealed by the Constitution of India.',\n", + " 'type': 'REPEALED_BY',\n", + " 'end': 'Constitution Of India'},\n", + " {'start': 'Constituent Assembly',\n", + " 'description': None,\n", + " 'type': 'DRAFTED_BY',\n", + " 'end': 'Constitution Of India'}]},\n", + " {'communityId': '0-25',\n", + " 'nodes': [{'id': 'President Of India',\n", + " 'description': 'The Supreme Commander of the Indian Armed Forces.',\n", + " 'type': 'Person'},\n", + " {'id': 'Nda',\n", + " 'description': 'A coalition of the BJP and its allies governing India since 2014.',\n", + " 'type': 'Political alliance'},\n", + " {'id': 'Government Of India',\n", + " 'description': 'Established a system of national parks and protected areas.',\n", + " 'type': 'Government'},\n", + " {'id': 'Narendra Modi',\n", + " 'description': 'Current Prime Minister of India since 26 May 2014.',\n", + " 'type': 'Person'},\n", + " {'id': 'New Delhi',\n", + " 'description': 'The seat of the Government of India.',\n", + " 'type': 'Location'},\n", + " {'id': 'Supreme Court',\n", + " 'description': 'The highest judicial forum and final court of appeal under the Constitution of India.',\n", + " 'type': 'Judiciary'},\n", + " {'id': 'Indian Councils Act 1909',\n", + " 'description': 'Introduced elections to the Imperial Legislative Council.',\n", + " 'type': 'Legislation'},\n", + " {'id': 'Government Of India Act 1919',\n", + " 'description': 'Expanded the Imperial Legislative Council.',\n", + " 'type': 'Legislation'},\n", + " {'id': 'National Parks',\n", + " 'description': 'Established in 1935 and expanded to nearly 1022 by 2023.',\n", + " 'type': 'Protected area'},\n", + " {'id': 'Wildlife Protection Act Of 1972',\n", + " 'description': 'Enacted for the protection of wildlife.',\n", + " 'type': 'Legislation'},\n", + " {'id': 'Project Tiger',\n", + " 'description': 'Special project for the protection of critical species.',\n", + " 'type': 'Conservation project'},\n", + " {'id': 'Project Elephant',\n", + " 'description': 'Special project for the protection of critical species.',\n", + " 'type': 'Conservation project'},\n", + " {'id': 'Project Dolphin',\n", + " 'description': 'Special project for the protection of critical species.',\n", + " 'type': 'Conservation project'}],\n", + " 'rels': [{'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'INITIATED',\n", + " 'end': 'Project Tiger'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'INITIATED',\n", + " 'end': 'Project Elephant'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'INITIATED',\n", + " 'end': 'Project Dolphin'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'GOVERNED_BY',\n", + " 'end': 'Nda'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'ENACTED',\n", + " 'end': 'Wildlife Protection Act Of 1972'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'ESTABLISHED',\n", + " 'end': 'National Parks'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'LEAD_BY',\n", + " 'end': 'Narendra Modi'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'RESPONSIBLE_TO',\n", + " 'end': 'Supreme Court'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'SEATED_IN',\n", + " 'end': 'New Delhi'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'HEAD_OF_STATE',\n", + " 'end': 'President Of India'},\n", + " {'start': 'Indian Councils Act 1909',\n", + " 'description': None,\n", + " 'type': 'INFLUENCED',\n", + " 'end': 'Government Of India'},\n", + " {'start': 'Government Of India Act 1919',\n", + " 'description': None,\n", + " 'type': 'INFLUENCED',\n", + " 'end': 'Government Of India'}]},\n", + " {'communityId': '0-112',\n", + " 'nodes': [{'id': 'Prime Minister Of India',\n", + " 'description': 'Holds executive authority and responsibility for national security.',\n", + " 'type': 'Person'},\n", + " {'id': 'Indian Armed Forces',\n", + " 'description': 'The military forces of the Republic of India.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Indian Army',\n", + " 'description': 'One of the three professional uniformed services of the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Indian Navy',\n", + " 'description': 'One of the three professional uniformed services of the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Indian Air Force',\n", + " 'description': 'One of the three professional uniformed services of the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Central Armed Police Forces',\n", + " 'description': 'Supports the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Indian Coast Guard',\n", + " 'description': 'Supports the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Special Frontier Force',\n", + " 'description': 'Supports the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Strategic Forces Command',\n", + " 'description': 'An inter-service command of the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Andaman And Nicobar Command',\n", + " 'description': 'An inter-service command of the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Integrated Defence Staff',\n", + " 'description': 'An inter-service command of the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Ministry Of Defence',\n", + " 'description': 'Manages the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Global Firepower Index',\n", + " 'description': 'Ranks the military forces globally.',\n", + " 'type': 'Report'},\n", + " {'id': 'Armed Forces Flag Day',\n", + " 'description': 'Honors armed forces and military personnel annually.',\n", + " 'type': 'Event'},\n", + " {'id': 'Mauryan Empire',\n", + " 'description': 'An ancient Indian empire known for its powerful military.',\n", + " 'type': 'Empire'},\n", + " {'id': 'Chola Empire',\n", + " 'description': 'Known for foreign trade and maritime activity.',\n", + " 'type': 'Empire'}],\n", + " 'rels': [{'start': 'Prime Minister Of India',\n", + " 'description': None,\n", + " 'type': 'EXECUTIVE_AUTHORITY',\n", + " 'end': 'Indian Armed Forces'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Indian Army'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Indian Navy'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Indian Air Force'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'SUPPORTED_BY',\n", + " 'end': 'Central Armed Police Forces'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'SUPPORTED_BY',\n", + " 'end': 'Indian Coast Guard'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'SUPPORTED_BY',\n", + " 'end': 'Special Frontier Force'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'SUPPORTED_BY',\n", + " 'end': 'Strategic Forces Command'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'SUPPORTED_BY',\n", + " 'end': 'Andaman And Nicobar Command'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'SUPPORTED_BY',\n", + " 'end': 'Integrated Defence Staff'},\n", + " {'start': 'Ministry Of Defence',\n", + " 'description': None,\n", + " 'type': 'MANAGES',\n", + " 'end': 'Indian Armed Forces'},\n", + " {'start': 'Global Firepower Index',\n", + " 'description': None,\n", + " 'type': 'RANKS',\n", + " 'end': 'Indian Armed Forces'},\n", + " {'start': 'Armed Forces Flag Day',\n", + " 'description': None,\n", + " 'type': 'HONORS',\n", + " 'end': 'Indian Armed Forces'},\n", + " {'start': 'Mauryan Empire',\n", + " 'description': None,\n", + " 'type': 'HISTORICAL_REFERENCE',\n", + " 'end': 'Indian Armed Forces'},\n", + " {'start': 'Chola Empire',\n", + " 'description': None,\n", + " 'type': 'HISTORICAL_REFERENCE',\n", + " 'end': 'Indian Armed Forces'}]},\n", + " {'communityId': '0-27',\n", + " 'nodes': [{'id': 'Rajya Sabha',\n", + " 'description': 'The mostly indirectly elected upper house of Parliament.',\n", + " 'type': 'Government body'},\n", + " {'id': 'Lok Sabha',\n", + " 'description': 'The directly elected lower house of Parliament.',\n", + " 'type': 'Government body'},\n", + " {'id': 'Union Council Of Ministers',\n", + " 'description': 'The executive decision-making committee of the government.',\n", + " 'type': 'Government body'}],\n", + " 'rels': [{'start': 'Union Council Of Ministers',\n", + " 'description': None,\n", + " 'type': 'RESPONSIBLE_TO',\n", + " 'end': 'Rajya Sabha'},\n", + " {'start': 'Union Council Of Ministers',\n", + " 'description': None,\n", + " 'type': 'RESPONSIBLE_TO',\n", + " 'end': 'Lok Sabha'}]},\n", + " {'communityId': '0-11',\n", + " 'nodes': [{'id': 'Republic Of India',\n", + " 'description': 'Has two principal official short names, India and Bharat.',\n", + " 'type': 'Country'},\n", + " {'id': 'Hindustan',\n", + " 'description': 'Commonly used name for the Republic of India.',\n", + " 'type': 'Name'}],\n", + " 'rels': [{'start': 'Republic Of India',\n", + " 'description': None,\n", + " 'type': 'HAS_NAME',\n", + " 'end': 'Hindustan'}]},\n", + " {'communityId': '0-15',\n", + " 'nodes': [{'id': 'Bharat',\n", + " 'description': 'Another principal official short name of the Republic of India.',\n", + " 'type': 'Name'},\n", + " {'id': 'Dushyanta',\n", + " 'description': 'Father of Bharata, associated with the name Bhāratavarṣa.',\n", + " 'type': 'Person'},\n", + " {'id': 'Mahabharata',\n", + " 'description': 'Epic associated with the name Bharata.',\n", + " 'type': 'Literature'}],\n", + " 'rels': [{'start': 'Bharat',\n", + " 'description': None,\n", + " 'type': 'ASSOCIATED_WITH',\n", + " 'end': 'Dushyanta'},\n", + " {'start': 'Bharat',\n", + " 'description': None,\n", + " 'type': 'ASSOCIATED_WITH',\n", + " 'end': 'Mahabharata'}]},\n", + " {'communityId': '0-14',\n", + " 'nodes': [{'id': 'Bhāratavarṣa',\n", + " 'description': 'Term used in the first century AD, derived from the name of the Vedic community of Bharatas.',\n", + " 'type': 'Historical term'},\n", + " {'id': 'Bharatas',\n", + " 'description': 'Mentioned in the Rigveda as one of the principal kingdoms of the Aryavarta.',\n", + " 'type': 'Vedic community'}],\n", + " 'rels': [{'start': 'Bhāratavarṣa',\n", + " 'description': None,\n", + " 'type': 'DERIVED_FROM',\n", + " 'end': 'Bharatas'}]},\n", + " {'communityId': '0-39',\n", + " 'nodes': [{'id': 'Thailand',\n", + " 'description': \"Shares maritime borders with India's Andaman and Nicobar Islands.\",\n", + " 'type': 'Country'},\n", + " {'id': 'Indonesia',\n", + " 'description': \"Shares maritime borders with India's Andaman and Nicobar Islands.\",\n", + " 'type': 'Country'},\n", + " {'id': 'Andaman And Nicobar Islands',\n", + " 'description': 'Islands of India sharing a maritime border with Thailand, Myanmar, and Indonesia.',\n", + " 'type': 'Island'}],\n", + " 'rels': [{'start': 'Andaman And Nicobar Islands',\n", + " 'description': None,\n", + " 'type': 'MARITIME_BORDER',\n", + " 'end': 'Thailand'},\n", + " {'start': 'Andaman And Nicobar Islands',\n", + " 'description': None,\n", + " 'type': 'MARITIME_BORDER',\n", + " 'end': 'Indonesia'}]},\n", + " {'communityId': '0-52',\n", + " 'nodes': [{'id': 'Constituent Assembly Of India',\n", + " 'description': 'Adopted the Constitution of India on 26 November 1949.',\n", + " 'type': 'Institution'},\n", + " {'id': 'Sardar Patel',\n", + " 'description': 'Convinced princely states to sign articles of integration with India.',\n", + " 'type': 'Person'},\n", + " {'id': 'V. P. Menon',\n", + " 'description': 'Convinced princely states to sign articles of integration with India.',\n", + " 'type': 'Person'}],\n", + " 'rels': [{'start': 'Sardar Patel',\n", + " 'description': 'Convinced princely states to sign articles of integration.',\n", + " 'type': 'CONVINCED',\n", + " 'end': 'Constituent Assembly Of India'},\n", + " {'start': 'V. P. Menon',\n", + " 'description': 'Convinced princely states to sign articles of integration.',\n", + " 'type': 'CONVINCED',\n", + " 'end': 'Constituent Assembly Of India'}]},\n", + " {'communityId': '0-78',\n", + " 'nodes': [{'id': 'Fauna Species',\n", + " 'description': 'India has an estimated 92,873 species of fauna.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Insects',\n", + " 'description': 'Major category with 63,423 recorded species.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Mammals Count',\n", + " 'description': '423 mammals in India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Birds Count',\n", + " 'description': '1,233 birds in India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Reptiles Count',\n", + " 'description': '526 reptiles in India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Amphibians Count',\n", + " 'description': '342 amphibians in India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Fish Count',\n", + " 'description': '3,022 fish in India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Endemic Mammals',\n", + " 'description': '12.6% of mammals are endemic to India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Endemic Birds',\n", + " 'description': '4.5% of birds are endemic to India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Endemic Reptiles',\n", + " 'description': '45.8% of reptiles are endemic to India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Endemic Amphibians',\n", + " 'description': '55.8% of amphibians are endemic to India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Large Animals',\n", + " 'description': 'Includes Indian elephant, Indian rhinoceros, and Gaur.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Big Cats',\n", + " 'description': 'Includes tiger and lion.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Cat Family',\n", + " 'description': 'Includes Bengal tiger, Asiatic lion, Indian leopard, snow leopard, and clouded leopard.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Representative Species',\n", + " 'description': 'Includes blackbuck, nilgai, bharal, barasingha, Nilgiri tahr, and Nilgiri langur.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Aquatic Mammals',\n", + " 'description': 'Includes dolphins, whales, porpoises, and dugong.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Reptiles Species',\n", + " 'description': 'Includes gharial and saltwater crocodiles.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Birds Species',\n", + " 'description': 'Includes peafowl, pheasants, geese, ducks, mynas, parakeets, pigeons, cranes, hornbills, and sunbirds.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Endemic Bird Species',\n", + " 'description': 'Includes great Indian hornbill, great Indian bustard, nicobar pigeon, ruddy shelduck, Himalayan monal, and Himalayan quail.',\n", + " 'type': 'Fauna'}],\n", + " 'rels': [{'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Insects'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Mammals Count'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Birds Count'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Reptiles Count'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Amphibians Count'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Fish Count'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Endemic Mammals'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Endemic Birds'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Endemic Reptiles'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Endemic Amphibians'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Large Animals'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Big Cats'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Cat Family'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Representative Species'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Aquatic Mammals'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Reptiles Species'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Birds Species'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Endemic Bird Species'}]},\n", + " {'communityId': '0-110',\n", + " 'nodes': [{'id': 'Plant Species',\n", + " 'description': 'About 29,015 species of plants.',\n", + " 'type': 'Flora'},\n", + " {'id': 'Flowering Plants Count',\n", + " 'description': '17,926 species of flowering plants.',\n", + " 'type': 'Flora'},\n", + " {'id': 'Endemic Plant Species',\n", + " 'description': '6,842 species are endemic to India.',\n", + " 'type': 'Flora'},\n", + " {'id': 'Algae', 'description': '7,244 species.', 'type': 'Flora'},\n", + " {'id': 'Bryophytes', 'description': '2,504 species.', 'type': 'Flora'},\n", + " {'id': 'Pteridophytes', 'description': '1,267 species.', 'type': 'Flora'},\n", + " {'id': 'Gymnosperms', 'description': '74 species.', 'type': 'Flora'},\n", + " {'id': 'Fungal Diversity',\n", + " 'description': 'Over 27,000 recorded species.',\n", + " 'type': 'Flora'},\n", + " {'id': 'Flora', 'description': None, 'type': None}],\n", + " 'rels': [{'start': 'Flora',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Plant Species'},\n", + " {'start': 'Flora',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Flowering Plants Count'},\n", + " {'start': 'Flora',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Endemic Plant Species'},\n", + " {'start': 'Flora', 'description': None, 'type': 'INCLUDES', 'end': 'Algae'},\n", + " {'start': 'Flora',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Bryophytes'},\n", + " {'start': 'Flora',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Pteridophytes'},\n", + " {'start': 'Flora',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Gymnosperms'},\n", + " {'start': 'Flora',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Fungal Diversity'}]},\n", + " {'communityId': '0-105',\n", + " 'nodes': [{'id': 'Threatened Species',\n", + " 'description': '172 IUCN-designated threatened species.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Threatened Mammals',\n", + " 'description': '39 species of mammals.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Threatened Birds',\n", + " 'description': '72 species of birds.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Threatened Reptiles',\n", + " 'description': '17 species of reptiles.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Threatened Amphibians',\n", + " 'description': '3 species of amphibians.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Threatened Fish',\n", + " 'description': '2 species of fish.',\n", + " 'type': 'Fauna'}],\n", + " 'rels': [{'start': 'Threatened Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Threatened Mammals'},\n", + " {'start': 'Threatened Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Threatened Birds'},\n", + " {'start': 'Threatened Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Threatened Reptiles'},\n", + " {'start': 'Threatened Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Threatened Amphibians'},\n", + " {'start': 'Threatened Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Threatened Fish'}]},\n", + " {'communityId': '0-125',\n", + " 'nodes': [{'id': 'Department Of Defence Production',\n", + " 'description': 'Responsible for indigenous production of equipment for the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Make In India Initiative',\n", + " 'description': 'Seeks to indigenise manufacturing and reduce dependence on imports for defence.',\n", + " 'type': 'Program'}],\n", + " 'rels': [{'start': 'Make In India Initiative',\n", + " 'description': None,\n", + " 'type': 'SUPPORTS',\n", + " 'end': 'Department Of Defence Production'}]},\n", + " {'communityId': '0-169',\n", + " 'nodes': [{'id': 'Maurya Empire',\n", + " 'description': 'Ancient empire based in the Ganges Basin.',\n", + " 'type': 'Empire'},\n", + " {'id': 'Gupta Empire',\n", + " 'description': 'Ancient empire based in the Ganges Basin.',\n", + " 'type': 'Empire'},\n", + " {'id': 'Ganges Basin', 'description': None, 'type': None}],\n", + " 'rels': [{'start': 'Ganges Basin',\n", + " 'description': None,\n", + " 'type': 'BASED_IN',\n", + " 'end': 'Maurya Empire'},\n", + " {'start': 'Ganges Basin',\n", + " 'description': None,\n", + " 'type': 'BASED_IN',\n", + " 'end': 'Gupta Empire'}]},\n", + " {'communityId': '0-170',\n", + " 'nodes': [{'id': 'Vijayanagara Empire',\n", + " 'description': 'Empire in south India that created a composite Hindu culture.',\n", + " 'type': 'Empire'},\n", + " {'id': 'South India', 'description': None, 'type': None}],\n", + " 'rels': [{'start': 'South India',\n", + " 'description': None,\n", + " 'type': 'BASED_IN',\n", + " 'end': 'Vijayanagara Empire'}]},\n", + " {'communityId': '0-171',\n", + " 'nodes': [{'id': 'Sikhism',\n", + " 'description': 'Religion that emerged in the Punjab, rejecting institutionalised religion.',\n", + " 'type': 'Religion'},\n", + " {'id': 'Punjab', 'description': None, 'type': None}],\n", + " 'rels': [{'start': 'Punjab',\n", + " 'description': None,\n", + " 'type': 'ORIGIN_OF',\n", + " 'end': 'Sikhism'}]},\n", + " {'communityId': '0-167',\n", + " 'nodes': [{'id': 'British East India Company',\n", + " 'description': 'Company that expanded rule in India, turning it into a colonial economy.',\n", + " 'type': 'Company'},\n", + " {'id': 'British Crown',\n", + " 'description': 'Began rule in India in 1858.',\n", + " 'type': 'Government'},\n", + " {'id': 'Indian Independence',\n", + " 'description': 'Event in 1947 when India was partitioned into two independent dominions.',\n", + " 'type': 'Event'}],\n", + " 'rels': [{'start': 'British East India Company',\n", + " 'description': None,\n", + " 'type': 'HISTORICAL_EVENT',\n", + " 'end': 'British Crown'},\n", + " {'start': 'British Crown',\n", + " 'description': None,\n", + " 'type': 'HISTORICAL_EVENT',\n", + " 'end': 'Indian Independence'}]},\n", + " {'communityId': '1-23',\n", + " 'nodes': [{'id': 'India',\n", + " 'description': 'Officially the Republic of India, located in South Asia.',\n", + " 'type': 'Country'},\n", + " {'id': 'Supreme Court Of India',\n", + " 'description': 'Head of the independent judiciary.',\n", + " 'type': 'Judiciary'},\n", + " {'id': 'Indian National Congress',\n", + " 'description': 'Dominated Indian politics until 1977.',\n", + " 'type': 'Political party'},\n", + " {'id': 'Sindhu',\n", + " 'description': 'Name of the Indus River, from which the name India is derived.',\n", + " 'type': 'River'},\n", + " {'id': 'Food And Agriculture Organization Of The United Nations',\n", + " 'description': \"Estimates India's forest cover.\",\n", + " 'type': 'Organization'},\n", + " {'id': '2013 Forest Survey Of India',\n", + " 'description': \"States India's forest cover increased to 69.8 million hectares by 2012.\",\n", + " 'type': 'Report'},\n", + " {'id': 'Yajnavalkya Smriti',\n", + " 'description': 'Prohibited the cutting of trees.',\n", + " 'type': 'Literature'},\n", + " {'id': 'Kautalyas Arthashastra',\n", + " 'description': 'Discusses the need for forest administration.',\n", + " 'type': 'Literature'},\n", + " {'id': 'Crown Land (Encroachment) Ordinance',\n", + " 'description': \"Promulgated in 1840 targeting forests in Britain's Asian colonies.\",\n", + " 'type': 'Legislation'},\n", + " {'id': 'Indian Forest Act Of 1865',\n", + " 'description': \"Established the government's claims over forests.\",\n", + " 'type': 'Legislation'},\n", + " {'id': 'Forest Act Of 1878',\n", + " 'description': 'Gave the British government control over all wastelands, including forests.',\n", + " 'type': 'Legislation'},\n", + " {'id': 'Sir Dietrich Brandis',\n", + " 'description': 'Inspector General of Forests in India from 1864 to 1883.',\n", + " 'type': 'Person'},\n", + " {'id': 'Indian Ocean',\n", + " 'description': 'Ocean bounded by India on the north.',\n", + " 'type': 'Ocean'},\n", + " {'id': 'Sri Lanka',\n", + " 'description': 'Country in the vicinity of India in the Indian Ocean.',\n", + " 'type': 'Country'},\n", + " {'id': 'Maldives',\n", + " 'description': 'Country in the vicinity of India in the Indian Ocean.',\n", + " 'type': 'Country'},\n", + " {'id': 'Myanmar',\n", + " 'description': 'Country sharing land border with India to the east.',\n", + " 'type': 'Country'},\n", + " {'id': 'Himalayan Mountain Range',\n", + " 'description': 'Defines the northern frontiers of India.',\n", + " 'type': 'Mountain range'},\n", + " {'id': 'China',\n", + " 'description': 'Country sharing land border with India to the north.',\n", + " 'type': 'Country'},\n", + " {'id': 'Bhutan',\n", + " 'description': 'Country sharing land border with India to the north.',\n", + " 'type': 'Country'},\n", + " {'id': 'Nepal',\n", + " 'description': 'Country sharing land border with India to the north.',\n", + " 'type': 'Country'},\n", + " {'id': 'Pakistan',\n", + " 'description': 'Country sharing land border with India to the west.',\n", + " 'type': 'Country'},\n", + " {'id': 'Bangladesh',\n", + " 'description': 'Country sharing land border with India to the east.',\n", + " 'type': 'Country'},\n", + " {'id': 'Ganges',\n", + " 'description': 'The longest river originating in India.',\n", + " 'type': 'River'},\n", + " {'id': 'Western Ghats',\n", + " 'description': 'One of the three biodiversity hotspots in India.',\n", + " 'type': 'Biodiversity hotspot'},\n", + " {'id': 'Eastern Himalayas',\n", + " 'description': 'One of the three biodiversity hotspots in India.',\n", + " 'type': 'Biodiversity hotspot'},\n", + " {'id': 'Indo-Burma Hotspot',\n", + " 'description': 'One of the three biodiversity hotspots in India.',\n", + " 'type': 'Biodiversity hotspot'},\n", + " {'id': 'Forests',\n", + " 'description': 'Covers about 24.6% of the total land area.',\n", + " 'type': 'Ecosystem'},\n", + " {'id': 'Indomalayan Realm',\n", + " 'description': 'Geographical realm that includes India.',\n", + " 'type': 'Realm'},\n", + " {'id': 'World', 'description': None, 'type': None},\n", + " {'id': 'Public_Sector', 'description': None, 'type': None},\n", + " {'id': 'Gdp', 'description': None, 'type': None},\n", + " {'id': 'Economic_Liberalisation', 'description': None, 'type': None},\n", + " {'id': 'Gdp_Growth', 'description': None, 'type': None},\n", + " {'id': 'Consumer_Market', 'description': None, 'type': None},\n", + " {'id': 'Wto', 'description': None, 'type': None},\n", + " {'id': 'Ease_Of_Business_Index', 'description': None, 'type': None},\n", + " {'id': 'Global_Competitiveness_Index', 'description': None, 'type': None},\n", + " {'id': 'Billionaires', 'description': None, 'type': None},\n", + " {'id': 'Welfare_State', 'description': None, 'type': None},\n", + " {'id': 'Socialist_State', 'description': None, 'type': None},\n", + " {'id': 'Social_Welfare_Spending', 'description': None, 'type': None},\n", + " {'id': 'Labour_Force', 'description': None, 'type': None},\n", + " {'id': 'Fdi', 'description': None, 'type': None},\n", + " {'id': 'Free_Trade_Agreements', 'description': None, 'type': None},\n", + " {'id': 'Service_Sector', 'description': None, 'type': None},\n", + " {'id': 'Stock_Exchanges', 'description': None, 'type': None},\n", + " {'id': 'Manufacturing', 'description': None, 'type': None},\n", + " {'id': 'Population', 'description': None, 'type': None},\n", + " {'id': 'Unemployment', 'description': None, 'type': None},\n", + " {'id': 'Savings_Rate', 'description': None, 'type': None},\n", + " {'id': 'Arabian Sea',\n", + " 'description': 'Sea bounded by India on the northwest.',\n", + " 'type': 'Sea'},\n", + " {'id': 'Bay Of Bengal',\n", + " 'description': 'Bay bounded by India on the southeast.',\n", + " 'type': 'Bay'},\n", + " {'id': 'Africa',\n", + " 'description': 'Continent from which modern humans arrived on the Indian subcontinent.',\n", + " 'type': 'Continent'},\n", + " {'id': 'Indus Valley Civilisation',\n", + " 'description': 'Civilisation that evolved from settled life in the western margins of the Indus river basin.',\n", + " 'type': 'Civilization'},\n", + " {'id': 'Sanskrit',\n", + " 'description': 'Indo-European language that diffused into India from the northwest.',\n", + " 'type': 'Language'},\n", + " {'id': 'Rigveda',\n", + " 'description': 'Ancient hymns recording the dawning of Hinduism in India.',\n", + " 'type': 'Text'},\n", + " {'id': 'Hinduism',\n", + " 'description': 'Major religion in India, with roots in the Rigveda.',\n", + " 'type': 'Religion'},\n", + " {'id': 'Buddhism',\n", + " 'description': 'Religion that arose in India, proclaiming social orders unlinked to heredity.',\n", + " 'type': 'Religion'},\n", + " {'id': 'Jainism',\n", + " 'description': 'Religion that arose in India, proclaiming social orders unlinked to heredity.',\n", + " 'type': 'Religion'},\n", + " {'id': 'Mughal Empire',\n", + " 'description': 'Empire that began in 1526, known for its architecture and relative peace.',\n", + " 'type': 'Empire'},\n", + " {'id': 'Indian Republic',\n", + " 'description': 'India has been a federal republic since 1950.',\n", + " 'type': 'Government'},\n", + " {'id': 'Thailand',\n", + " 'description': \"Shares maritime borders with India's Andaman and Nicobar Islands.\",\n", + " 'type': 'Country'},\n", + " {'id': 'Indonesia',\n", + " 'description': \"Shares maritime borders with India's Andaman and Nicobar Islands.\",\n", + " 'type': 'Country'},\n", + " {'id': 'Andaman And Nicobar Islands',\n", + " 'description': 'Islands of India sharing a maritime border with Thailand, Myanmar, and Indonesia.',\n", + " 'type': 'Island'}],\n", + " 'rels': [{'start': 'India',\n", + " 'description': None,\n", + " 'type': 'IS_PART_OF',\n", + " 'end': 'Indomalayan Realm'},\n", + " {'start': 'India',\n", + " 'description': 'About 1,900 public sector companies with complete control and ownership of railways, highways, and majority control in various industries.',\n", + " 'type': 'HAS',\n", + " 'end': 'Public_Sector'},\n", + " {'start': 'India',\n", + " 'description': \"One of the world's highest number of billionaires.\",\n", + " 'type': 'HAS',\n", + " 'end': 'Billionaires'},\n", + " {'start': 'India',\n", + " 'description': \"World's second-largest labour force with 586 million workers.\",\n", + " 'type': 'HAS',\n", + " 'end': 'Labour_Force'},\n", + " {'start': 'India',\n", + " 'description': 'Has free trade agreements with several nations and blocs.',\n", + " 'type': 'HAS',\n", + " 'end': 'Free_Trade_Agreements'},\n", + " {'start': 'India',\n", + " 'description': \"Bombay Stock Exchange and National Stock Exchange are among the world's largest stock exchanges.\",\n", + " 'type': 'HAS',\n", + " 'end': 'Stock_Exchanges'},\n", + " {'start': 'India',\n", + " 'description': \"Nearly 65% of India's population is rural.\",\n", + " 'type': 'HAS',\n", + " 'end': 'Population'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'RELATES_TO',\n", + " 'end': 'Rigveda'},\n", + " {'start': 'India',\n", + " 'description': 'Member of the World Trade Organization since 1 January 1995.',\n", + " 'type': 'MEMBER_OF',\n", + " 'end': 'Wto'},\n", + " {'start': 'India',\n", + " 'description': 'High unemployment and rising income inequality.',\n", + " 'type': 'FACES',\n", + " 'end': 'Unemployment'},\n", + " {'start': 'India',\n", + " 'description': 'Adopted broad economic liberalisation in 1991.',\n", + " 'type': 'ADOPTED',\n", + " 'end': 'Economic_Liberalisation'},\n", + " {'start': 'India',\n", + " 'description': 'Often considered a welfare state.',\n", + " 'type': 'CONSIDERED_AS',\n", + " 'end': 'Welfare_State'},\n", + " {'start': 'India', 'description': None, 'type': 'NEAR', 'end': 'Sri Lanka'},\n", + " {'start': 'India', 'description': None, 'type': 'NEAR', 'end': 'Maldives'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'BORDERS',\n", + " 'end': 'Indian Ocean'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'BORDERS',\n", + " 'end': 'Myanmar'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'BORDERS',\n", + " 'end': 'Himalayan Mountain Range'},\n", + " {'start': 'India', 'description': None, 'type': 'BORDERS', 'end': 'China'},\n", + " {'start': 'India', 'description': None, 'type': 'BORDERS', 'end': 'Bhutan'},\n", + " {'start': 'India', 'description': None, 'type': 'BORDERS', 'end': 'Nepal'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'BORDERS',\n", + " 'end': 'Pakistan'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'BORDERS',\n", + " 'end': 'Bangladesh'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'BORDERS',\n", + " 'end': 'Arabian Sea'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'BORDERS',\n", + " 'end': 'Bay Of Bengal'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'SEPARATED_BY',\n", + " 'end': 'Sri Lanka'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'DERIVED_FROM',\n", + " 'end': 'Sindhu'},\n", + " {'start': 'India',\n", + " 'description': \"Estimates India's forest cover.\",\n", + " 'type': 'ESTIMATES',\n", + " 'end': 'Food And Agriculture Organization Of The United Nations'},\n", + " {'start': 'India',\n", + " 'description': 'Makes up more than 50% of GDP.',\n", + " 'type': 'MAKES_UP',\n", + " 'end': 'Service_Sector'},\n", + " {'start': 'India',\n", + " 'description': 'Fifth-largest economy by nominal GDP and third-largest by purchasing power parity (PPP).',\n", + " 'type': 'RANKS_AS',\n", + " 'end': 'World'},\n", + " {'start': 'India',\n", + " 'description': 'Fourth-largest consumer market in the world.',\n", + " 'type': 'RANKS_AS',\n", + " 'end': 'Consumer_Market'},\n", + " {'start': 'India',\n", + " 'description': \"World's sixth-largest manufacturer, representing 2.6% of global manufacturing output.\",\n", + " 'type': 'RANKS_AS',\n", + " 'end': 'Manufacturing'},\n", + " {'start': 'India',\n", + " 'description': 'Officially declared a socialist state as per the constitution.',\n", + " 'type': 'DECLARED_AS',\n", + " 'end': 'Socialist_State'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'ORIGIN_OF',\n", + " 'end': 'Hinduism'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'ORIGIN_OF',\n", + " 'end': 'Buddhism'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'ORIGIN_OF',\n", + " 'end': 'Jainism'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'GOVERNED_AS',\n", + " 'end': 'Indian Republic'},\n", + " {'start': 'India',\n", + " 'description': '136th by GDP (nominal) and 125th by GDP (PPP) on a per capita income basis.',\n", + " 'type': 'RANKS',\n", + " 'end': 'Gdp'},\n", + " {'start': 'India',\n", + " 'description': '63rd on the Ease of Doing Business index.',\n", + " 'type': 'RANKS',\n", + " 'end': 'Ease_Of_Business_Index'},\n", + " {'start': 'India',\n", + " 'description': '40th on the Global Competitiveness Index.',\n", + " 'type': 'RANKS',\n", + " 'end': 'Global_Competitiveness_Index'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'SHARES_BORDERS_WITH',\n", + " 'end': 'Myanmar'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'SHARES_BORDERS_WITH',\n", + " 'end': 'Thailand'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'SHARES_BORDERS_WITH',\n", + " 'end': 'Indonesia'},\n", + " {'start': 'India',\n", + " 'description': 'Overall social welfare spending stood at 8.6% of GDP in 2021-22.',\n", + " 'type': 'SPENDING',\n", + " 'end': 'Social_Welfare_Spending'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'HISTORICAL_EVENT',\n", + " 'end': 'Mughal Empire'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'ORIGINATES_IN',\n", + " 'end': 'Ganges'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'HAS_BIODIVERSITY_HOTSPOT',\n", + " 'end': 'Western Ghats'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'HAS_BIODIVERSITY_HOTSPOT',\n", + " 'end': 'Eastern Himalayas'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'HAS_BIODIVERSITY_HOTSPOT',\n", + " 'end': 'Indo-Burma Hotspot'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'HAS_ECOSYSTEM',\n", + " 'end': 'Forests'},\n", + " {'start': 'India',\n", + " 'description': '6% to 7% since the start of the 21st century.',\n", + " 'type': 'AVERAGE_ANNUAL_GROWTH',\n", + " 'end': 'Gdp_Growth'},\n", + " {'start': 'India',\n", + " 'description': 'Foreign direct investment in 2021-22 was $82 billion.',\n", + " 'type': 'FOREIGN_DIRECT_INVESTMENT',\n", + " 'end': 'Fdi'},\n", + " {'start': 'India',\n", + " 'description': 'Gross domestic savings rate stood at 29.3% of GDP in 2022.',\n", + " 'type': 'GROSS_DOMESTIC_SAVINGS_RATE',\n", + " 'end': 'Savings_Rate'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'HUMAN_ORIGIN',\n", + " 'end': 'Africa'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'HISTORICAL_DEVELOPMENT',\n", + " 'end': 'Indus Valley Civilisation'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'LANGUAGE_DIFFUSION',\n", + " 'end': 'Sanskrit'},\n", + " {'start': 'Kautalyas Arthashastra',\n", + " 'description': 'Discusses the need for forest administration.',\n", + " 'type': 'DISCUSSES',\n", + " 'end': 'India'},\n", + " {'start': 'Indian Forest Act Of 1865',\n", + " 'description': \"Establishes government's claims over forests.\",\n", + " 'type': 'ESTABLISHES',\n", + " 'end': 'India'},\n", + " {'start': 'Crown Land (Encroachment) Ordinance',\n", + " 'description': \"Targets forests in Britain's Asian colonies.\",\n", + " 'type': 'TARGETS',\n", + " 'end': 'India'},\n", + " {'start': 'Yajnavalkya Smriti',\n", + " 'description': 'Prohibits the cutting of trees.',\n", + " 'type': 'PROHIBITS',\n", + " 'end': 'India'},\n", + " {'start': '2013 Forest Survey Of India',\n", + " 'description': 'Reports on forest cover increase.',\n", + " 'type': 'REPORTS_ON',\n", + " 'end': 'India'},\n", + " {'start': 'Supreme Court Of India',\n", + " 'description': None,\n", + " 'type': 'PART_OF_JUDICIARY',\n", + " 'end': 'India'},\n", + " {'start': 'Indian National Congress',\n", + " 'description': None,\n", + " 'type': 'HISTORICALLY_DOMINANT_PARTY',\n", + " 'end': 'India'},\n", + " {'start': 'Forest Act Of 1878',\n", + " 'description': 'Gives control over all wastelands, including forests.',\n", + " 'type': 'GIVES_CONTROL',\n", + " 'end': 'India'},\n", + " {'start': 'Sir Dietrich Brandis',\n", + " 'description': 'Inspector General of Forests in India from 1864 to 1883.',\n", + " 'type': 'INSPECTOR_GENERAL_OF',\n", + " 'end': 'India'},\n", + " {'start': 'Andaman And Nicobar Islands',\n", + " 'description': None,\n", + " 'type': 'MARITIME_BORDER',\n", + " 'end': 'Myanmar'},\n", + " {'start': 'Andaman And Nicobar Islands',\n", + " 'description': None,\n", + " 'type': 'MARITIME_BORDER',\n", + " 'end': 'Thailand'},\n", + " {'start': 'Andaman And Nicobar Islands',\n", + " 'description': None,\n", + " 'type': 'MARITIME_BORDER',\n", + " 'end': 'Indonesia'}]},\n", + " {'communityId': '1-7',\n", + " 'nodes': [{'id': 'Constitution Of India',\n", + " 'description': 'The supreme law of India, laying down the framework for government institutions and fundamental rights.',\n", + " 'type': 'Document'},\n", + " {'id': 'Parliament',\n", + " 'description': 'Cannot override the Constitution of India.',\n", + " 'type': 'Institution'},\n", + " {'id': 'Government Of India Act 1935',\n", + " 'description': 'Replaced by the Constitution of India.',\n", + " 'type': 'Document'},\n", + " {'id': 'Constituent Assembly',\n", + " 'description': 'Tasked with drafting the Constitution of India.',\n", + " 'type': 'Government body'},\n", + " {'id': 'M. N. Roy',\n", + " 'description': 'Proposed the framework for the Constitution of India.',\n", + " 'type': 'Person'},\n", + " {'id': 'Republic Day',\n", + " 'description': 'Celebrated on 26 January in India to honor the Constitution.',\n", + " 'type': 'Event'},\n", + " {'id': 'Old Parliament House',\n", + " 'description': 'Preserves the original 1950 Constitution in a nitrogen-filled case.',\n", + " 'type': 'Location'},\n", + " {'id': 'British Government',\n", + " 'description': 'Responsible for the external security of India during its dominion status.',\n", + " 'type': 'Institution'},\n", + " {'id': 'Indian Independence Act 1947',\n", + " 'description': 'Repealed by the Constitution of India.',\n", + " 'type': 'Document'},\n", + " {'id': 'Articles Of The Constitution',\n", + " 'description': 'Articles 5, 6, 7, 8, 9, 60, 324, 366, 367, 379, 380, 388, 391, 392, 393, and 394 came into force on 26 November 1949.',\n", + " 'type': 'Document'},\n", + " {'id': 'Constituent Assembly Of India',\n", + " 'description': 'Adopted the Constitution of India on 26 November 1949.',\n", + " 'type': 'Institution'},\n", + " {'id': 'Sardar Patel',\n", + " 'description': 'Convinced princely states to sign articles of integration with India.',\n", + " 'type': 'Person'},\n", + " {'id': 'V. P. Menon',\n", + " 'description': 'Convinced princely states to sign articles of integration with India.',\n", + " 'type': 'Person'}],\n", + " 'rels': [{'start': 'Constitution Of India',\n", + " 'description': 'The Constitution is based on the proposal suggested by M. N. Roy.',\n", + " 'type': 'BASED_ON',\n", + " 'end': 'M. N. Roy'},\n", + " {'start': 'Constitution Of India',\n", + " 'description': 'Adopted by the Constituent Assembly on 26 November 1949.',\n", + " 'type': 'ADOPTED_BY',\n", + " 'end': 'Constituent Assembly Of India'},\n", + " {'start': 'Constitution Of India',\n", + " 'description': 'The original 1950 Constitution is preserved in a nitrogen-filled case.',\n", + " 'type': 'PRESERVED_IN',\n", + " 'end': 'Old Parliament House'},\n", + " {'start': 'Constitution Of India',\n", + " 'description': 'Celebrated on 26 January.',\n", + " 'type': 'CELEBRATED_ON',\n", + " 'end': 'Republic Day'},\n", + " {'start': 'Constitution Of India',\n", + " 'description': 'Parliament cannot override the Constitution.',\n", + " 'type': 'CANNOT_OVERRIDE',\n", + " 'end': 'Parliament'},\n", + " {'start': 'Constitution Of India',\n", + " 'description': 'Certain articles came into force on 26 November 1949.',\n", + " 'type': 'CAME_INTO_FORCE',\n", + " 'end': 'Articles Of The Constitution'},\n", + " {'start': 'Government Of India Act 1935',\n", + " 'description': 'Replaced by the Constitution of India.',\n", + " 'type': 'REPLACED_BY',\n", + " 'end': 'Constitution Of India'},\n", + " {'start': 'British Government',\n", + " 'description': 'Responsible for the external security of India during its dominion status.',\n", + " 'type': 'RESPONSIBLE_FOR',\n", + " 'end': 'Constitution Of India'},\n", + " {'start': 'Indian Independence Act 1947',\n", + " 'description': 'Repealed by the Constitution of India.',\n", + " 'type': 'REPEALED_BY',\n", + " 'end': 'Constitution Of India'},\n", + " {'start': 'Constituent Assembly',\n", + " 'description': None,\n", + " 'type': 'DRAFTED_BY',\n", + " 'end': 'Constitution Of India'},\n", + " {'start': 'Sardar Patel',\n", + " 'description': 'Convinced princely states to sign articles of integration.',\n", + " 'type': 'CONVINCED',\n", + " 'end': 'Constituent Assembly Of India'},\n", + " {'start': 'V. P. Menon',\n", + " 'description': 'Convinced princely states to sign articles of integration.',\n", + " 'type': 'CONVINCED',\n", + " 'end': 'Constituent Assembly Of India'}]},\n", + " {'communityId': '1-4',\n", + " 'nodes': [{'id': 'President Of India',\n", + " 'description': 'The Supreme Commander of the Indian Armed Forces.',\n", + " 'type': 'Person'},\n", + " {'id': 'Nda',\n", + " 'description': 'A coalition of the BJP and its allies governing India since 2014.',\n", + " 'type': 'Political alliance'},\n", + " {'id': 'Government Of India',\n", + " 'description': 'Established a system of national parks and protected areas.',\n", + " 'type': 'Government'},\n", + " {'id': 'Narendra Modi',\n", + " 'description': 'Current Prime Minister of India since 26 May 2014.',\n", + " 'type': 'Person'},\n", + " {'id': 'New Delhi',\n", + " 'description': 'The seat of the Government of India.',\n", + " 'type': 'Location'},\n", + " {'id': 'Supreme Court',\n", + " 'description': 'The highest judicial forum and final court of appeal under the Constitution of India.',\n", + " 'type': 'Judiciary'},\n", + " {'id': 'Indian Councils Act 1909',\n", + " 'description': 'Introduced elections to the Imperial Legislative Council.',\n", + " 'type': 'Legislation'},\n", + " {'id': 'Government Of India Act 1919',\n", + " 'description': 'Expanded the Imperial Legislative Council.',\n", + " 'type': 'Legislation'},\n", + " {'id': 'National Parks',\n", + " 'description': 'Established in 1935 and expanded to nearly 1022 by 2023.',\n", + " 'type': 'Protected area'},\n", + " {'id': 'Wildlife Protection Act Of 1972',\n", + " 'description': 'Enacted for the protection of wildlife.',\n", + " 'type': 'Legislation'},\n", + " {'id': 'Project Tiger',\n", + " 'description': 'Special project for the protection of critical species.',\n", + " 'type': 'Conservation project'},\n", + " {'id': 'Project Elephant',\n", + " 'description': 'Special project for the protection of critical species.',\n", + " 'type': 'Conservation project'},\n", + " {'id': 'Project Dolphin',\n", + " 'description': 'Special project for the protection of critical species.',\n", + " 'type': 'Conservation project'},\n", + " {'id': 'Rajya Sabha',\n", + " 'description': 'The mostly indirectly elected upper house of Parliament.',\n", + " 'type': 'Government body'},\n", + " {'id': 'Lok Sabha',\n", + " 'description': 'The directly elected lower house of Parliament.',\n", + " 'type': 'Government body'},\n", + " {'id': 'Union Council Of Ministers',\n", + " 'description': 'The executive decision-making committee of the government.',\n", + " 'type': 'Government body'}],\n", + " 'rels': [{'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'INITIATED',\n", + " 'end': 'Project Tiger'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'INITIATED',\n", + " 'end': 'Project Elephant'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'INITIATED',\n", + " 'end': 'Project Dolphin'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'GOVERNED_BY',\n", + " 'end': 'Nda'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'COMPOSED_OF',\n", + " 'end': 'Union Council Of Ministers'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'ENACTED',\n", + " 'end': 'Wildlife Protection Act Of 1972'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'ESTABLISHED',\n", + " 'end': 'National Parks'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'LEAD_BY',\n", + " 'end': 'Narendra Modi'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'RESPONSIBLE_TO',\n", + " 'end': 'Supreme Court'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'SEATED_IN',\n", + " 'end': 'New Delhi'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'HEAD_OF_STATE',\n", + " 'end': 'President Of India'},\n", + " {'start': 'Indian Councils Act 1909',\n", + " 'description': None,\n", + " 'type': 'INFLUENCED',\n", + " 'end': 'Government Of India'},\n", + " {'start': 'Government Of India Act 1919',\n", + " 'description': None,\n", + " 'type': 'INFLUENCED',\n", + " 'end': 'Government Of India'},\n", + " {'start': 'Union Council Of Ministers',\n", + " 'description': None,\n", + " 'type': 'RESPONSIBLE_TO',\n", + " 'end': 'Rajya Sabha'},\n", + " {'start': 'Union Council Of Ministers',\n", + " 'description': None,\n", + " 'type': 'RESPONSIBLE_TO',\n", + " 'end': 'Lok Sabha'}]},\n", + " {'communityId': '1-22',\n", + " 'nodes': [{'id': 'Prime Minister Of India',\n", + " 'description': 'Holds executive authority and responsibility for national security.',\n", + " 'type': 'Person'},\n", + " {'id': 'Indian Armed Forces',\n", + " 'description': 'The military forces of the Republic of India.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Indian Army',\n", + " 'description': 'One of the three professional uniformed services of the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Indian Navy',\n", + " 'description': 'One of the three professional uniformed services of the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Indian Air Force',\n", + " 'description': 'One of the three professional uniformed services of the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Central Armed Police Forces',\n", + " 'description': 'Supports the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Indian Coast Guard',\n", + " 'description': 'Supports the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Special Frontier Force',\n", + " 'description': 'Supports the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Strategic Forces Command',\n", + " 'description': 'An inter-service command of the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Andaman And Nicobar Command',\n", + " 'description': 'An inter-service command of the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Integrated Defence Staff',\n", + " 'description': 'An inter-service command of the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Ministry Of Defence',\n", + " 'description': 'Manages the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Global Firepower Index',\n", + " 'description': 'Ranks the military forces globally.',\n", + " 'type': 'Report'},\n", + " {'id': 'Armed Forces Flag Day',\n", + " 'description': 'Honors armed forces and military personnel annually.',\n", + " 'type': 'Event'},\n", + " {'id': 'Mauryan Empire',\n", + " 'description': 'An ancient Indian empire known for its powerful military.',\n", + " 'type': 'Empire'},\n", + " {'id': 'Chola Empire',\n", + " 'description': 'Known for foreign trade and maritime activity.',\n", + " 'type': 'Empire'},\n", + " {'id': 'Department Of Defence Production',\n", + " 'description': 'Responsible for indigenous production of equipment for the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Make In India Initiative',\n", + " 'description': 'Seeks to indigenise manufacturing and reduce dependence on imports for defence.',\n", + " 'type': 'Program'}],\n", + " 'rels': [{'start': 'Prime Minister Of India',\n", + " 'description': None,\n", + " 'type': 'EXECUTIVE_AUTHORITY',\n", + " 'end': 'Indian Armed Forces'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Indian Army'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Indian Navy'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Indian Air Force'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'SUPPORTED_BY',\n", + " 'end': 'Central Armed Police Forces'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'SUPPORTED_BY',\n", + " 'end': 'Indian Coast Guard'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'SUPPORTED_BY',\n", + " 'end': 'Special Frontier Force'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'SUPPORTED_BY',\n", + " 'end': 'Strategic Forces Command'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'SUPPORTED_BY',\n", + " 'end': 'Andaman And Nicobar Command'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'SUPPORTED_BY',\n", + " 'end': 'Integrated Defence Staff'},\n", + " {'start': 'Ministry Of Defence',\n", + " 'description': None,\n", + " 'type': 'MANAGES',\n", + " 'end': 'Indian Armed Forces'},\n", + " {'start': 'Global Firepower Index',\n", + " 'description': None,\n", + " 'type': 'RANKS',\n", + " 'end': 'Indian Armed Forces'},\n", + " {'start': 'Armed Forces Flag Day',\n", + " 'description': None,\n", + " 'type': 'HONORS',\n", + " 'end': 'Indian Armed Forces'},\n", + " {'start': 'Department Of Defence Production',\n", + " 'description': None,\n", + " 'type': 'PRODUCES_EQUIPMENT_FOR',\n", + " 'end': 'Indian Armed Forces'},\n", + " {'start': 'Mauryan Empire',\n", + " 'description': None,\n", + " 'type': 'HISTORICAL_REFERENCE',\n", + " 'end': 'Indian Armed Forces'},\n", + " {'start': 'Chola Empire',\n", + " 'description': None,\n", + " 'type': 'HISTORICAL_REFERENCE',\n", + " 'end': 'Indian Armed Forces'},\n", + " {'start': 'Make In India Initiative',\n", + " 'description': None,\n", + " 'type': 'SUPPORTS',\n", + " 'end': 'Department Of Defence Production'}]},\n", + " {'communityId': '1-2',\n", + " 'nodes': [{'id': 'Republic Of India',\n", + " 'description': 'Has two principal official short names, India and Bharat.',\n", + " 'type': 'Country'},\n", + " {'id': 'Hindustan',\n", + " 'description': 'Commonly used name for the Republic of India.',\n", + " 'type': 'Name'},\n", + " {'id': 'Bharat',\n", + " 'description': 'Another principal official short name of the Republic of India.',\n", + " 'type': 'Name'},\n", + " {'id': 'Dushyanta',\n", + " 'description': 'Father of Bharata, associated with the name Bhāratavarṣa.',\n", + " 'type': 'Person'},\n", + " {'id': 'Mahabharata',\n", + " 'description': 'Epic associated with the name Bharata.',\n", + " 'type': 'Literature'},\n", + " {'id': 'Bhāratavarṣa',\n", + " 'description': 'Term used in the first century AD, derived from the name of the Vedic community of Bharatas.',\n", + " 'type': 'Historical term'},\n", + " {'id': 'Bharatas',\n", + " 'description': 'Mentioned in the Rigveda as one of the principal kingdoms of the Aryavarta.',\n", + " 'type': 'Vedic community'}],\n", + " 'rels': [{'start': 'Republic Of India',\n", + " 'description': None,\n", + " 'type': 'HAS_NAME',\n", + " 'end': 'Bharat'},\n", + " {'start': 'Republic Of India',\n", + " 'description': None,\n", + " 'type': 'HAS_NAME',\n", + " 'end': 'Hindustan'},\n", + " {'start': 'Bharat',\n", + " 'description': None,\n", + " 'type': 'ASSOCIATED_WITH',\n", + " 'end': 'Dushyanta'},\n", + " {'start': 'Bharat',\n", + " 'description': None,\n", + " 'type': 'ASSOCIATED_WITH',\n", + " 'end': 'Mahabharata'},\n", + " {'start': 'Bharat',\n", + " 'description': None,\n", + " 'type': 'DERIVED_FROM',\n", + " 'end': 'Bhāratavarṣa'},\n", + " {'start': 'Bhāratavarṣa',\n", + " 'description': None,\n", + " 'type': 'DERIVED_FROM',\n", + " 'end': 'Bharatas'}]},\n", + " {'communityId': '1-18',\n", + " 'nodes': [{'id': 'Fauna Species',\n", + " 'description': 'India has an estimated 92,873 species of fauna.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Insects',\n", + " 'description': 'Major category with 63,423 recorded species.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Mammals Count',\n", + " 'description': '423 mammals in India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Birds Count',\n", + " 'description': '1,233 birds in India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Reptiles Count',\n", + " 'description': '526 reptiles in India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Amphibians Count',\n", + " 'description': '342 amphibians in India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Fish Count',\n", + " 'description': '3,022 fish in India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Endemic Mammals',\n", + " 'description': '12.6% of mammals are endemic to India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Endemic Birds',\n", + " 'description': '4.5% of birds are endemic to India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Endemic Reptiles',\n", + " 'description': '45.8% of reptiles are endemic to India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Endemic Amphibians',\n", + " 'description': '55.8% of amphibians are endemic to India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Large Animals',\n", + " 'description': 'Includes Indian elephant, Indian rhinoceros, and Gaur.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Big Cats',\n", + " 'description': 'Includes tiger and lion.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Cat Family',\n", + " 'description': 'Includes Bengal tiger, Asiatic lion, Indian leopard, snow leopard, and clouded leopard.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Representative Species',\n", + " 'description': 'Includes blackbuck, nilgai, bharal, barasingha, Nilgiri tahr, and Nilgiri langur.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Aquatic Mammals',\n", + " 'description': 'Includes dolphins, whales, porpoises, and dugong.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Reptiles Species',\n", + " 'description': 'Includes gharial and saltwater crocodiles.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Birds Species',\n", + " 'description': 'Includes peafowl, pheasants, geese, ducks, mynas, parakeets, pigeons, cranes, hornbills, and sunbirds.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Endemic Bird Species',\n", + " 'description': 'Includes great Indian hornbill, great Indian bustard, nicobar pigeon, ruddy shelduck, Himalayan monal, and Himalayan quail.',\n", + " 'type': 'Fauna'}],\n", + " 'rels': [{'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Insects'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Mammals Count'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Birds Count'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Reptiles Count'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Amphibians Count'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Fish Count'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Endemic Mammals'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Endemic Birds'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Endemic Reptiles'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Endemic Amphibians'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Large Animals'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Big Cats'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Cat Family'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Representative Species'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Aquatic Mammals'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Reptiles Species'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Birds Species'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Endemic Bird Species'}]},\n", + " {'communityId': '1-20',\n", + " 'nodes': [{'id': 'Plant Species',\n", + " 'description': 'About 29,015 species of plants.',\n", + " 'type': 'Flora'},\n", + " {'id': 'Flowering Plants Count',\n", + " 'description': '17,926 species of flowering plants.',\n", + " 'type': 'Flora'},\n", + " {'id': 'Endemic Plant Species',\n", + " 'description': '6,842 species are endemic to India.',\n", + " 'type': 'Flora'},\n", + " {'id': 'Algae', 'description': '7,244 species.', 'type': 'Flora'},\n", + " {'id': 'Bryophytes', 'description': '2,504 species.', 'type': 'Flora'},\n", + " {'id': 'Pteridophytes', 'description': '1,267 species.', 'type': 'Flora'},\n", + " {'id': 'Gymnosperms', 'description': '74 species.', 'type': 'Flora'},\n", + " {'id': 'Fungal Diversity',\n", + " 'description': 'Over 27,000 recorded species.',\n", + " 'type': 'Flora'},\n", + " {'id': 'Flora', 'description': None, 'type': None}],\n", + " 'rels': [{'start': 'Flora',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Plant Species'},\n", + " {'start': 'Flora',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Flowering Plants Count'},\n", + " {'start': 'Flora',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Endemic Plant Species'},\n", + " {'start': 'Flora', 'description': None, 'type': 'INCLUDES', 'end': 'Algae'},\n", + " {'start': 'Flora',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Bryophytes'},\n", + " {'start': 'Flora',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Pteridophytes'},\n", + " {'start': 'Flora',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Gymnosperms'},\n", + " {'start': 'Flora',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Fungal Diversity'}]},\n", + " {'communityId': '1-19',\n", + " 'nodes': [{'id': 'Threatened Species',\n", + " 'description': '172 IUCN-designated threatened species.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Threatened Mammals',\n", + " 'description': '39 species of mammals.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Threatened Birds',\n", + " 'description': '72 species of birds.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Threatened Reptiles',\n", + " 'description': '17 species of reptiles.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Threatened Amphibians',\n", + " 'description': '3 species of amphibians.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Threatened Fish',\n", + " 'description': '2 species of fish.',\n", + " 'type': 'Fauna'}],\n", + " 'rels': [{'start': 'Threatened Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Threatened Mammals'},\n", + " {'start': 'Threatened Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Threatened Birds'},\n", + " {'start': 'Threatened Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Threatened Reptiles'},\n", + " {'start': 'Threatened Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Threatened Amphibians'},\n", + " {'start': 'Threatened Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Threatened Fish'}]},\n", + " {'communityId': '1-25',\n", + " 'nodes': [{'id': 'Maurya Empire',\n", + " 'description': 'Ancient empire based in the Ganges Basin.',\n", + " 'type': 'Empire'},\n", + " {'id': 'Gupta Empire',\n", + " 'description': 'Ancient empire based in the Ganges Basin.',\n", + " 'type': 'Empire'},\n", + " {'id': 'Ganges Basin', 'description': None, 'type': None}],\n", + " 'rels': [{'start': 'Ganges Basin',\n", + " 'description': None,\n", + " 'type': 'BASED_IN',\n", + " 'end': 'Maurya Empire'},\n", + " {'start': 'Ganges Basin',\n", + " 'description': None,\n", + " 'type': 'BASED_IN',\n", + " 'end': 'Gupta Empire'}]},\n", + " {'communityId': '1-26',\n", + " 'nodes': [{'id': 'Vijayanagara Empire',\n", + " 'description': 'Empire in south India that created a composite Hindu culture.',\n", + " 'type': 'Empire'},\n", + " {'id': 'South India', 'description': None, 'type': None}],\n", + " 'rels': [{'start': 'South India',\n", + " 'description': None,\n", + " 'type': 'BASED_IN',\n", + " 'end': 'Vijayanagara Empire'}]},\n", + " {'communityId': '1-27',\n", + " 'nodes': [{'id': 'Sikhism',\n", + " 'description': 'Religion that emerged in the Punjab, rejecting institutionalised religion.',\n", + " 'type': 'Religion'},\n", + " {'id': 'Punjab', 'description': None, 'type': None}],\n", + " 'rels': [{'start': 'Punjab',\n", + " 'description': None,\n", + " 'type': 'ORIGIN_OF',\n", + " 'end': 'Sikhism'}]},\n", + " {'communityId': '1-24',\n", + " 'nodes': [{'id': 'British East India Company',\n", + " 'description': 'Company that expanded rule in India, turning it into a colonial economy.',\n", + " 'type': 'Company'},\n", + " {'id': 'British Crown',\n", + " 'description': 'Began rule in India in 1858.',\n", + " 'type': 'Government'},\n", + " {'id': 'Indian Independence',\n", + " 'description': 'Event in 1947 when India was partitioned into two independent dominions.',\n", + " 'type': 'Event'}],\n", + " 'rels': [{'start': 'British East India Company',\n", + " 'description': None,\n", + " 'type': 'HISTORICAL_EVENT',\n", + " 'end': 'British Crown'},\n", + " {'start': 'British Crown',\n", + " 'description': None,\n", + " 'type': 'HISTORICAL_EVENT',\n", + " 'end': 'Indian Independence'}]}]" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "community_info" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "community_template = \"\"\"Based on the provided nodes and relationships that belong to the same graph community,\n", + "generate a natural language summary of the provided information:\n", + "{community_info}\n", + "\n", + "Summary:\"\"\" \n", + "model = \"openai-gpt-4o\"\n", + "llm, model_name = get_llm(model)\n", + "community_prompt = ChatPromptTemplate.from_messages(\n", + " [\n", + " (\n", + " \"system\",\n", + " \"Given an input triples, generate the information summary. No pre-amble.\",\n", + " ),\n", + " (\"human\", community_template),\n", + " ]\n", + ")\n", + "\n", + "community_chain = community_prompt | llm | StrOutputParser()" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "def prepare_string(data):\n", + " nodes_str = \"Nodes are:\\n\"\n", + " for node in data['nodes']:\n", + " node_id = node['id']\n", + " node_type = node['type']\n", + " if 'description' in node and node['description']:\n", + " node_description = f\", description: {node['description']}\"\n", + " else:\n", + " node_description = \"\"\n", + " nodes_str += f\"id: {node_id}, type: {node_type}{node_description}\\n\"\n", + "\n", + " rels_str = \"Relationships are:\\n\"\n", + " for rel in data['rels']:\n", + " start = rel['start']\n", + " end = rel['end']\n", + " rel_type = rel['type']\n", + " if 'description' in rel and rel['description']:\n", + " description = f\", description: {rel['description']}\"\n", + " else:\n", + " description = \"\"\n", + " rels_str += f\"({start})-[:{rel_type}]->({end}){description}\\n\"\n", + "\n", + " return nodes_str + \"\\n\" + rels_str\n", + "\n", + "def process_community(community):\n", + " stringify_info = prepare_string(community)\n", + " summary = community_chain.invoke({'community_info': stringify_info})\n", + " return {\"community\": community['communityId'], \"summary\": summary}" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Nodes are:\n", + "id: India, type: Country, description: Officially the Republic of India, located in South Asia.\n", + "id: Supreme Court Of India, type: Judiciary, description: Head of the independent judiciary.\n", + "id: Indian National Congress, type: Political party, description: Dominated Indian politics until 1977.\n", + "id: Sindhu, type: River, description: Name of the Indus River, from which the name India is derived.\n", + "id: Food And Agriculture Organization Of The United Nations, type: Organization, description: Estimates India's forest cover.\n", + "id: 2013 Forest Survey Of India, type: Report, description: States India's forest cover increased to 69.8 million hectares by 2012.\n", + "id: Yajnavalkya Smriti, type: Literature, description: Prohibited the cutting of trees.\n", + "id: Kautalyas Arthashastra, type: Literature, description: Discusses the need for forest administration.\n", + "id: Crown Land (Encroachment) Ordinance, type: Legislation, description: Promulgated in 1840 targeting forests in Britain's Asian colonies.\n", + "id: Indian Forest Act Of 1865, type: Legislation, description: Established the government's claims over forests.\n", + "id: Forest Act Of 1878, type: Legislation, description: Gave the British government control over all wastelands, including forests.\n", + "id: Sir Dietrich Brandis, type: Person, description: Inspector General of Forests in India from 1864 to 1883.\n", + "id: Indian Ocean, type: Ocean, description: Ocean bounded by India on the north.\n", + "id: Sri Lanka, type: Country, description: Country in the vicinity of India in the Indian Ocean.\n", + "id: Maldives, type: Country, description: Country in the vicinity of India in the Indian Ocean.\n", + "id: Myanmar, type: Country, description: Country sharing land border with India to the east.\n", + "id: Himalayan Mountain Range, type: Mountain range, description: Defines the northern frontiers of India.\n", + "id: China, type: Country, description: Country sharing land border with India to the north.\n", + "id: Bhutan, type: Country, description: Country sharing land border with India to the north.\n", + "id: Nepal, type: Country, description: Country sharing land border with India to the north.\n", + "id: Pakistan, type: Country, description: Country sharing land border with India to the west.\n", + "id: Bangladesh, type: Country, description: Country sharing land border with India to the east.\n", + "id: Ganges, type: River, description: The longest river originating in India.\n", + "id: Western Ghats, type: Biodiversity hotspot, description: One of the three biodiversity hotspots in India.\n", + "id: Eastern Himalayas, type: Biodiversity hotspot, description: One of the three biodiversity hotspots in India.\n", + "id: Indo-Burma Hotspot, type: Biodiversity hotspot, description: One of the three biodiversity hotspots in India.\n", + "id: Forests, type: Ecosystem, description: Covers about 24.6% of the total land area.\n", + "id: Indomalayan Realm, type: Realm, description: Geographical realm that includes India.\n", + "id: World, type: None\n", + "id: Public_Sector, type: None\n", + "id: Gdp, type: None\n", + "id: Economic_Liberalisation, type: None\n", + "id: Gdp_Growth, type: None\n", + "id: Consumer_Market, type: None\n", + "id: Wto, type: None\n", + "id: Ease_Of_Business_Index, type: None\n", + "id: Global_Competitiveness_Index, type: None\n", + "id: Billionaires, type: None\n", + "id: Welfare_State, type: None\n", + "id: Socialist_State, type: None\n", + "id: Social_Welfare_Spending, type: None\n", + "id: Labour_Force, type: None\n", + "id: Fdi, type: None\n", + "id: Free_Trade_Agreements, type: None\n", + "id: Service_Sector, type: None\n", + "id: Stock_Exchanges, type: None\n", + "id: Manufacturing, type: None\n", + "id: Population, type: None\n", + "id: Unemployment, type: None\n", + "id: Savings_Rate, type: None\n", + "id: Arabian Sea, type: Sea, description: Sea bounded by India on the northwest.\n", + "id: Bay Of Bengal, type: Bay, description: Bay bounded by India on the southeast.\n", + "id: Africa, type: Continent, description: Continent from which modern humans arrived on the Indian subcontinent.\n", + "id: Indus Valley Civilisation, type: Civilization, description: Civilisation that evolved from settled life in the western margins of the Indus river basin.\n", + "id: Sanskrit, type: Language, description: Indo-European language that diffused into India from the northwest.\n", + "id: Rigveda, type: Text, description: Ancient hymns recording the dawning of Hinduism in India.\n", + "id: Hinduism, type: Religion, description: Major religion in India, with roots in the Rigveda.\n", + "id: Buddhism, type: Religion, description: Religion that arose in India, proclaiming social orders unlinked to heredity.\n", + "id: Jainism, type: Religion, description: Religion that arose in India, proclaiming social orders unlinked to heredity.\n", + "id: Mughal Empire, type: Empire, description: Empire that began in 1526, known for its architecture and relative peace.\n", + "id: Indian Republic, type: Government, description: India has been a federal republic since 1950.\n", + "\n", + "Relationships are:\n", + "(India)-[:IS_PART_OF]->(Indomalayan Realm)\n", + "(India)-[:HAS]->(Public_Sector), description: About 1,900 public sector companies with complete control and ownership of railways, highways, and majority control in various industries.\n", + "(India)-[:HAS]->(Billionaires), description: One of the world's highest number of billionaires.\n", + "(India)-[:HAS]->(Labour_Force), description: World's second-largest labour force with 586 million workers.\n", + "(India)-[:HAS]->(Free_Trade_Agreements), description: Has free trade agreements with several nations and blocs.\n", + "(India)-[:HAS]->(Stock_Exchanges), description: Bombay Stock Exchange and National Stock Exchange are among the world's largest stock exchanges.\n", + "(India)-[:HAS]->(Population), description: Nearly 65% of India's population is rural.\n", + "(India)-[:RELATES_TO]->(Rigveda)\n", + "(India)-[:MEMBER_OF]->(Wto), description: Member of the World Trade Organization since 1 January 1995.\n", + "(India)-[:FACES]->(Unemployment), description: High unemployment and rising income inequality.\n", + "(India)-[:ADOPTED]->(Economic_Liberalisation), description: Adopted broad economic liberalisation in 1991.\n", + "(India)-[:CONSIDERED_AS]->(Welfare_State), description: Often considered a welfare state.\n", + "(India)-[:NEAR]->(Sri Lanka)\n", + "(India)-[:NEAR]->(Maldives)\n", + "(India)-[:BORDERS]->(Indian Ocean)\n", + "(India)-[:BORDERS]->(Myanmar)\n", + "(India)-[:BORDERS]->(Himalayan Mountain Range)\n", + "(India)-[:BORDERS]->(China)\n", + "(India)-[:BORDERS]->(Bhutan)\n", + "(India)-[:BORDERS]->(Nepal)\n", + "(India)-[:BORDERS]->(Pakistan)\n", + "(India)-[:BORDERS]->(Bangladesh)\n", + "(India)-[:BORDERS]->(Arabian Sea)\n", + "(India)-[:BORDERS]->(Bay Of Bengal)\n", + "(India)-[:SEPARATED_BY]->(Sri Lanka)\n", + "(India)-[:DERIVED_FROM]->(Sindhu)\n", + "(India)-[:ESTIMATES]->(Food And Agriculture Organization Of The United Nations), description: Estimates India's forest cover.\n", + "(India)-[:MAKES_UP]->(Service_Sector), description: Makes up more than 50% of GDP.\n", + "(India)-[:RANKS_AS]->(World), description: Fifth-largest economy by nominal GDP and third-largest by purchasing power parity (PPP).\n", + "(India)-[:RANKS_AS]->(Consumer_Market), description: Fourth-largest consumer market in the world.\n", + "(India)-[:RANKS_AS]->(Manufacturing), description: World's sixth-largest manufacturer, representing 2.6% of global manufacturing output.\n", + "(India)-[:DECLARED_AS]->(Socialist_State), description: Officially declared a socialist state as per the constitution.\n", + "(India)-[:ORIGIN_OF]->(Hinduism)\n", + "(India)-[:ORIGIN_OF]->(Buddhism)\n", + "(India)-[:ORIGIN_OF]->(Jainism)\n", + "(India)-[:GOVERNED_AS]->(Indian Republic)\n", + "(India)-[:RANKS]->(Gdp), description: 136th by GDP (nominal) and 125th by GDP (PPP) on a per capita income basis.\n", + "(India)-[:RANKS]->(Ease_Of_Business_Index), description: 63rd on the Ease of Doing Business index.\n", + "(India)-[:RANKS]->(Global_Competitiveness_Index), description: 40th on the Global Competitiveness Index.\n", + "(India)-[:SHARES_BORDERS_WITH]->(Myanmar)\n", + "(India)-[:SPENDING]->(Social_Welfare_Spending), description: Overall social welfare spending stood at 8.6% of GDP in 2021-22.\n", + "(India)-[:HISTORICAL_EVENT]->(Mughal Empire)\n", + "(India)-[:ORIGINATES_IN]->(Ganges)\n", + "(India)-[:HAS_BIODIVERSITY_HOTSPOT]->(Western Ghats)\n", + "(India)-[:HAS_BIODIVERSITY_HOTSPOT]->(Eastern Himalayas)\n", + "(India)-[:HAS_BIODIVERSITY_HOTSPOT]->(Indo-Burma Hotspot)\n", + "(India)-[:HAS_ECOSYSTEM]->(Forests)\n", + "(India)-[:AVERAGE_ANNUAL_GROWTH]->(Gdp_Growth), description: 6% to 7% since the start of the 21st century.\n", + "(India)-[:FOREIGN_DIRECT_INVESTMENT]->(Fdi), description: Foreign direct investment in 2021-22 was $82 billion.\n", + "(India)-[:GROSS_DOMESTIC_SAVINGS_RATE]->(Savings_Rate), description: Gross domestic savings rate stood at 29.3% of GDP in 2022.\n", + "(India)-[:HUMAN_ORIGIN]->(Africa)\n", + "(India)-[:HISTORICAL_DEVELOPMENT]->(Indus Valley Civilisation)\n", + "(India)-[:LANGUAGE_DIFFUSION]->(Sanskrit)\n", + "(Kautalyas Arthashastra)-[:DISCUSSES]->(India), description: Discusses the need for forest administration.\n", + "(Indian Forest Act Of 1865)-[:ESTABLISHES]->(India), description: Establishes government's claims over forests.\n", + "(Crown Land (Encroachment) Ordinance)-[:TARGETS]->(India), description: Targets forests in Britain's Asian colonies.\n", + "(Yajnavalkya Smriti)-[:PROHIBITS]->(India), description: Prohibits the cutting of trees.\n", + "(2013 Forest Survey Of India)-[:REPORTS_ON]->(India), description: Reports on forest cover increase.\n", + "(Supreme Court Of India)-[:PART_OF_JUDICIARY]->(India)\n", + "(Indian National Congress)-[:HISTORICALLY_DOMINANT_PARTY]->(India)\n", + "(Forest Act Of 1878)-[:GIVES_CONTROL]->(India), description: Gives control over all wastelands, including forests.\n", + "(Sir Dietrich Brandis)-[:INSPECTOR_GENERAL_OF]->(India), description: Inspector General of Forests in India from 1864 to 1883.\n", + "\n" + ] + } + ], + "source": [ + "print(prepare_string(community_info[0]))" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Processing communities: 0%| | 0/30 [00:00 pd.DataFrame:\n", + " \"\"\"Executes a Cypher statement and returns a DataFrame\"\"\"\n", + " return driver.execute_query(\n", + " cypher, parameters_=params, result_transformer_=Result.to_df\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "## Calculate before \n", + "db_query(\n", + " \"\"\"\n", + "MATCH (n:`__Community__`)<-[:IN_COMMUNITY]-()<-[:HAS_ENTITY]-(c)\n", + "WITH n, count(distinct c) AS chunkCount\n", + "SET n.weight = chunkCount\"\"\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## local and global search" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "index_name = \"entity_local\"\n", + "\n", + "# db_query(\n", + "# \"\"\"\n", + "# CREATE VECTOR INDEX \"\"\"\n", + "# + index_name\n", + "# + \"\"\" IF NOT EXISTS FOR (e:__Entity__) ON e.embedding\n", + "# OPTIONS {indexConfig: {\n", + "# `vector.dimensions`: 384,\n", + "# `vector.similarity_function`: 'cosine'\n", + "# }}\n", + "# \"\"\"\n", + "# )" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "topChunks = 3\n", + "topCommunities = 3\n", + "topOutsideRels = 10\n", + "topInsideRels = 10\n", + "topEntities = 10" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "lc_retrieval_query = \"\"\"\n", + "WITH collect(node) as nodes\n", + "// Entity - Text Unit Mapping\n", + "WITH\n", + "collect {\n", + " UNWIND nodes as n\n", + " MATCH (n)<-[:HAS_ENTITY]->(c:Chunk)\n", + " WITH c, count(distinct n) as freq\n", + " RETURN c.text AS chunkText\n", + " ORDER BY freq DESC\n", + " LIMIT $topChunks\n", + "} AS text_mapping,\n", + "// Entity - Report Mapping\n", + "collect {\n", + " UNWIND nodes as n\n", + " MATCH (n)-[:IN_COMMUNITY]->(c:__Community__)\n", + " WITH c, c.rank as rank, c.weight AS weight\n", + " RETURN c.summary \n", + " ORDER BY rank, weight DESC\n", + " LIMIT $topCommunities\n", + "} AS report_mapping,\n", + "// Outside Relationships \n", + "collect {\n", + " UNWIND nodes as n\n", + " MATCH (n)-[r:RELATED]-(m) \n", + " WHERE NOT m IN nodes\n", + " RETURN r.description AS descriptionText\n", + " ORDER BY r.rank, r.weight DESC \n", + " LIMIT $topOutsideRels\n", + "} as outsideRels,\n", + "// Inside Relationships \n", + "collect {\n", + " UNWIND nodes as n\n", + " MATCH (n)-[r:RELATED]-(m) \n", + " WHERE m IN nodes\n", + " RETURN r.description AS descriptionText\n", + " ORDER BY r.rank, r.weight DESC \n", + " LIMIT $topInsideRels\n", + "} as insideRels,\n", + "// Entities description\n", + "collect {\n", + " UNWIND nodes as n\n", + " RETURN n.description AS descriptionText\n", + "} as entities\n", + "// We don't have covariates or claims here\n", + "RETURN {Chunks: text_mapping, Reports: report_mapping, \n", + " Relationships: outsideRels + insideRels, \n", + " Entities: entities} AS text, 1.0 AS score, {} AS metadata\n", + "\"\"\"\n", + "\n", + "embeddings, dimension = load_embedding_model(\"sentence_transformer\")\n", + "lc_vector = Neo4jVector.from_existing_index(\n", + " embeddings,\n", + " url=os.environ[\"NEO4J_URI\"],\n", + " username=os.environ[\"NEO4J_USERNAME\"],\n", + " password=os.environ[\"NEO4J_PASSWORD\"],\n", + " index_name=index_name,\n", + " retrieval_query=lc_retrieval_query,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "docs = lc_vector.similarity_search_with_score(\n", + " \"Major cities of India\",\n", + " k=topEntities,\n", + " params={\n", + " \"topChunks\": topChunks,\n", + " \"topCommunities\": topCommunities,\n", + " \"topOutsideRels\": topOutsideRels,\n", + " \"topInsideRels\": topInsideRels,\n", + " },\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Entities:\n", + "- None\n", + "- None\n", + "- None\n", + "- One of the three biodiversity hotspots in India.\n", + "- Officially the Republic of India, located in South Asia.\n", + "- Geographical realm that includes India.\n", + "- One of the three biodiversity hotspots in India.\n", + "- Defines the northern frontiers of India.\n", + "- One of the three biodiversity hotspots in India.\n", + "- Commonly used name for the Republic of India.\n", + "Reports:\n", + "- India, officially the Republic of India, is a country located in South Asia and is part of the Indomalayan Realm. It shares borders with several countries including China, Bhutan, Nepal, Pakistan, Bangladesh, and Myanmar, and is bounded by the Indian Ocean, Arabian Sea, and Bay of Bengal. India is known for its rich biodiversity, featuring hotspots like the Western Ghats, Eastern Himalayas, and Indo-Burma Hotspot, and has a significant forest cover, which has been increasing as reported by the 2013 Forest Survey of India.\n", + "\n", + "India has a complex history, with ancient civilizations like the Indus Valley Civilisation and significant cultural contributions such as the Rigveda, which marks the dawn of Hinduism. It is also the birthplace of Buddhism and Jainism. The country has a diverse linguistic heritage, including the diffusion of the Indo-European language Sanskrit.\n", + "\n", + "Economically, India is a major global player, ranking as the fifth-largest economy by nominal GDP and third-largest by purchasing power parity (PPP). It has a significant public sector, a large labor force, and is a member of the World Trade Organization. The country has adopted broad economic liberalization since 1991, leading to substantial GDP growth and a robust service sector that makes up more than 50% of its GDP. India also has a high number of billionaires and is considered a welfare state with significant social welfare spending.\n", + "\n", + "Politically, India has been a federal republic since 1950, with the Indian National Congress historically dominating its politics until 1977. The Supreme Court of India heads its independent judiciary. The country has a rich legislative history concerning forest administration, with significant acts like the Indian Forest Act of 1865 and the Forest Act of 1878, and contributions from figures like Sir Dietrich Brandis, the Inspector General of Forests from 1864 to 1883.\n", + "\n", + "India's geographical and cultural landscape is further enriched by its rivers, such as the Ganges and Sindhu (Indus River), and its proximity to neighboring countries like Sri Lanka and the Maldives. The country is also part of the larger Indomalayan Realm and has historical ties to Africa, from where modern humans arrived on the Indian subcontinent.\n", + "- India, officially the Republic of India, is a country located in South Asia and is part of the Indomalayan Realm. It shares borders with several countries including China, Bhutan, Nepal, Pakistan, Bangladesh, and Myanmar, and is bounded by the Indian Ocean, Arabian Sea, and Bay of Bengal. India is known for its rich biodiversity, featuring hotspots like the Western Ghats, Eastern Himalayas, and Indo-Burma Hotspot, and has a significant forest cover, which has been increasing as reported by the 2013 Forest Survey of India.\n", + "\n", + "India has a complex history, with ancient civilizations like the Indus Valley Civilisation and significant cultural contributions such as the Rigveda, which marks the dawn of Hinduism. It is also the birthplace of Buddhism and Jainism. The country has a diverse linguistic heritage, including the diffusion of the Indo-European language Sanskrit.\n", + "\n", + "Economically, India is a major global player, ranking as the fifth-largest economy by nominal GDP and third-largest by purchasing power parity (PPP). It has a significant public sector, a large labor force, and is a member of the World Trade Organization. The country has adopted broad economic liberalization since 1991, leading to substantial GDP growth and a robust service sector that makes up more than 50% of its GDP. India also has a high number of billionaires and is considered a welfare state with significant social welfare spending.\n", + "\n", + "Politically, India has been a federal republic since 1950, with the Indian National Congress historically dominating its politics until 1977. The Supreme Court of India heads its independent judiciary. The country has a rich legislative history concerning forest administration, with significant acts like the Indian Forest Act of 1865 and the Forest Act of 1878, and contributions from figures like Sir Dietrich Brandis, the Inspector General of Forests from 1864 to 1883.\n", + "\n", + "India's geographical and cultural landscape is further enriched by its rivers, such as the Ganges and Sindhu (Indus River), and its proximity to neighboring countries like Sri Lanka and the Maldives. The country is also part of the larger Indomalayan Realm and has historical ties to Africa, from where modern humans arrived on the Indian subcontinent.\n", + "- India, officially the Republic of India, is a country located in South Asia and is part of the Indomalayan Realm. It shares borders with several countries including China, Bhutan, Nepal, Pakistan, Bangladesh, and Myanmar, and is bounded by the Indian Ocean, Arabian Sea, and Bay of Bengal. India is known for its rich biodiversity, featuring hotspots like the Western Ghats, Eastern Himalayas, and Indo-Burma Hotspot, and has a significant forest cover, which has been increasing as reported by the 2013 Forest Survey of India.\n", + "\n", + "India has a complex history, with ancient civilizations like the Indus Valley Civilisation and significant cultural contributions such as the Rigveda, which marks the dawn of Hinduism. It is also the birthplace of Buddhism and Jainism. The country has a diverse linguistic heritage, including the diffusion of the Indo-European language Sanskrit.\n", + "\n", + "Economically, India is a major global player, ranking as the fifth-largest economy by nominal GDP and third-largest by purchasing power parity (PPP). It has a significant public sector, a large labor force, and is a member of the World Trade Organization. The country has adopted broad economic liberalization since 1991, leading to substantial GDP growth and a robust service sector that makes up more than 50% of its GDP. India also has a high number of billionaires and is considered a welfare state with significant social welfare spending.\n", + "\n", + "Politically, India has been a federal republic since 1950, with the Indian National Congress historically dominating its politics until 1977. The Supreme Court of India heads its independent judiciary. The country has a rich legislative history concerning forest administration, with significant acts like the Indian Forest Act of 1865 and the Forest Act of 1878, and contributions from figures like Sir Dietrich Brandis, the Inspector General of Forests from 1864 to 1883.\n", + "\n", + "India's geographical and cultural landscape is further enriched by its rivers, such as the Ganges and Sindhu (Indus River), and its proximity to neighboring countries like Sri Lanka and the Maldives. The country is also part of the larger Indomalayan Realm and has historical ties to Africa, from where modern humans arrived on the Indian subcontinent.\n", + "Chunks:\n", + "- India is one of the most biodiverse regions and is home to a large variety of wildlife. It is one of the 17 megadiverse countries and includes three of the worlds 36 biodiversity hotspots – the Western Ghats, the Eastern Himalayas, and the Indo-Burma hotspot. About 24.6% of the total land area is covered by forests. It has various ecosystems ranging from the high altitude Himalayas, tropical evergreen forests along the Western Ghats, desert in the north-west, coastal plains and mangroves along the peninsular region. India lies within the Indomalayan realm and is home to about 7.6% of mammal, 14.7% of amphibian, 6% of bird, 6.2% of reptilian, and 6.2% of flowering plant species. Human encroachment, deforestation and poaching are significant challenges that threaten the existence of certain fauna and flora. Government of India established a system of national parks and\n", + "- threaten the existence of certain fauna and flora. Government of India established a system of national parks and protected areas in 1935, which have been subsequently expanded to nearly 1022 protected areas by 2023. India has enacted the Wildlife Protection Act of 1972 and special projects such as Project Tiger, Project Elephant and Project Dolphin for protection of critical species. == Fauna == India has an estimated 92,873 species of fauna, roughly about 7.5% of the species available worldwide. Insects form the major category with 63423 recorded species. India is home to 423 mammals, 1233 birds, 526 reptiles, 342 amphibians, 3022 fish apart from other species which form 7.6% of mammal, 14.7% of amphibian, 6% of bird, 6.2% of reptilian species worldwide. Many Indian species are descendants of species originating in Gondwana, of which India originally was a part. Peninsular Indias subsequent movement towards\n", + "- Gondwana, of which India originally was a part. Peninsular Indias subsequent movement towards, and collision with, the Laurasian landmass set off a mass exchange of species. However, volcanism in the Deccan Traps and climatic change 20 million years ago caused the extinction of many endemic Indian forms. Soon thereafter, mammals entered India from Asia through two zoogeographical passes on either side of the emerging Himalayas. As a result, among Indian species, only 12.6% of mammals and 4.5% of birds are endemic, contrasting with 45.8% of reptiles and 55.8% of amphibians India is home to several well-known large animals, including the Indian elephant, Indian rhinoceros, and Gaur. India is the only country where the big cats tiger and lion exist in the wild. Members of the cat family include Bengal tiger, Asiatic lion, Indian leopard, snow leopard, and clouded\n", + "Relationships:\n", + "\n" + ] + } + ], + "source": [ + "print(docs[0][0].page_content)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "model = \"openai-gpt-4o\"\n", + "llm, model_name = get_llm(model)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "MAP_SYSTEM_PROMPT = \"\"\"\n", + "---Role---\n", + "\n", + "You are a helpful assistant responding to questions about data in the tables provided.\n", + "\n", + "\n", + "---Goal---\n", + "\n", + "Generate a response consisting of a list of key points that responds to the user's question, summarizing all relevant information in the input data tables.\n", + "\n", + "You should use the data provided in the data tables below as the primary context for generating the response.\n", + "If you don't know the answer or if the input data tables do not contain sufficient information to provide an answer, just say so. Do not make anything up.\n", + "\n", + "Each key point in the response should have the following element:\n", + "- Description: A comprehensive description of the point.\n", + "- Importance Score: An integer score between 0-100 that indicates how important the point is in answering the user's question. An 'I don't know' type of response should have a score of 0.\n", + "\n", + "The response should be JSON formatted as follows:\n", + "{{\n", + " \"points\": [\n", + " {{\"description\": \"Description of point 1 [Data: Reports (report ids)]\", \"score\": score_value}},\n", + " {{\"description\": \"Description of point 2 [Data: Reports (report ids)]\", \"score\": score_value}}\n", + " ]\n", + "}}\n", + "\n", + "The response shall preserve the original meaning and use of modal verbs such as \"shall\", \"may\" or \"will\".\n", + "\n", + "Points supported by data should list the relevant reports as references as follows:\n", + "\"This is an example sentence supported by data references [Data: Reports (report ids)]\"\n", + "\n", + "**Do not list more than 5 record ids in a single reference**. Instead, list the top 5 most relevant record ids and add \"+more\" to indicate that there are more.\n", + "\n", + "For example:\n", + "\"Person X is the owner of Company Y and subject to many allegations of wrongdoing [Data: Reports (2, 7, 64, 46, 34, +more)]. He is also CEO of company X [Data: Reports (1, 3)]\"\n", + "\n", + "where 1, 2, 3, 7, 34, 46, and 64 represent the id (not the index) of the relevant data report in the provided tables.\n", + "\n", + "Do not include information where the supporting evidence for it is not provided.\n", + "\n", + "\n", + "---Data tables---\n", + "\n", + "{context_data}\n", + "\n", + "---Goal---\n", + "\n", + "Generate a response consisting of a list of key points that responds to the user's question, summarizing all relevant information in the input data tables.\n", + "\n", + "You should use the data provided in the data tables below as the primary context for generating the response.\n", + "If you don't know the answer or if the input data tables do not contain sufficient information to provide an answer, just say so. Do not make anything up.\n", + "\n", + "Each key point in the response should have the following element:\n", + "- Description: A comprehensive description of the point.\n", + "- Importance Score: An integer score between 0-100 that indicates how important the point is in answering the user's question. An 'I don't know' type of response should have a score of 0.\n", + "\n", + "The response shall preserve the original meaning and use of modal verbs such as \"shall\", \"may\" or \"will\".\n", + "\n", + "Points supported by data should list the relevant reports as references as follows:\n", + "\"This is an example sentence supported by data references [Data: Reports (report ids)]\"\n", + "\n", + "**Do not list more than 5 record ids in a single reference**. Instead, list the top 5 most relevant record ids and add \"+more\" to indicate that there are more.\n", + "\n", + "For example:\n", + "\"Person X is the owner of Company Y and subject to many allegations of wrongdoing [Data: Reports (2, 7, 64, 46, 34, +more)]. He is also CEO of company X [Data: Reports (1, 3)]\"\n", + "\n", + "where 1, 2, 3, 7, 34, 46, and 64 represent the id (not the index) of the relevant data report in the provided tables.\n", + "\n", + "Do not include information where the supporting evidence for it is not provided.\n", + "\n", + "The response should be JSON formatted as follows:\n", + "{{\n", + " \"points\": [\n", + " {{\"description\": \"Description of point 1 [Data: Reports (report ids)]\", \"score\": score_value}},\n", + " {{\"description\": \"Description of point 2 [Data: Reports (report ids)]\", \"score\": score_value}}\n", + " ]\n", + "}}\n", + "\"\"\"\n", + "\n", + "map_prompt = ChatPromptTemplate.from_messages(\n", + " [\n", + " (\n", + " \"system\",\n", + " MAP_SYSTEM_PROMPT,\n", + " ),\n", + " (\n", + " \"human\",\n", + " \"{question}\",\n", + " ),\n", + " ]\n", + ")\n", + "\n", + "map_chain = map_prompt | llm | StrOutputParser()" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "REDUCE_SYSTEM_PROMPT = \"\"\"\n", + "---Role---\n", + "\n", + "You are a helpful assistant responding to questions about a dataset by synthesizing perspectives from multiple analysts.\n", + "\n", + "\n", + "---Goal---\n", + "\n", + "Generate a response of the target length and format that responds to the user's question, summarize all the reports from multiple analysts who focused on different parts of the dataset.\n", + "\n", + "Note that the analysts' reports provided below are ranked in the **descending order of importance**.\n", + "\n", + "If you don't know the answer or if the provided reports do not contain sufficient information to provide an answer, just say so. Do not make anything up.\n", + "\n", + "The final response should remove all irrelevant information from the analysts' reports and merge the cleaned information into a comprehensive answer that provides explanations of all the key points and implications appropriate for the response length and format.\n", + "\n", + "Add sections and commentary to the response as appropriate for the length and format. Style the response in markdown.\n", + "\n", + "The response shall preserve the original meaning and use of modal verbs such as \"shall\", \"may\" or \"will\".\n", + "\n", + "The response should also preserve all the data references previously included in the analysts' reports, but do not mention the roles of multiple analysts in the analysis process.\n", + "\n", + "**Do not list more than 5 record ids in a single reference**. Instead, list the top 5 most relevant record ids and add \"+more\" to indicate that there are more.\n", + "\n", + "For example:\n", + "\n", + "\"Person X is the owner of Company Y and subject to many allegations of wrongdoing [Data: Reports (2, 7, 34, 46, 64, +more)]. He is also CEO of company X [Data: Reports (1, 3)]\"\n", + "\n", + "where 1, 2, 3, 7, 34, 46, and 64 represent the id (not the index) of the relevant data record.\n", + "\n", + "Do not include information where the supporting evidence for it is not provided.\n", + "\n", + "\n", + "---Target response length and format---\n", + "\n", + "{response_type}\n", + "\n", + "\n", + "---Analyst Reports---\n", + "\n", + "{report_data}\n", + "\n", + "\n", + "---Goal---\n", + "\n", + "Generate a response of the target length and format that responds to the user's question, summarize all the reports from multiple analysts who focused on different parts of the dataset.\n", + "\n", + "Note that the analysts' reports provided below are ranked in the **descending order of importance**.\n", + "\n", + "If you don't know the answer or if the provided reports do not contain sufficient information to provide an answer, just say so. Do not make anything up.\n", + "\n", + "The final response should remove all irrelevant information from the analysts' reports and merge the cleaned information into a comprehensive answer that provides explanations of all the key points and implications appropriate for the response length and format.\n", + "\n", + "The response shall preserve the original meaning and use of modal verbs such as \"shall\", \"may\" or \"will\".\n", + "\n", + "The response should also preserve all the data references previously included in the analysts' reports, but do not mention the roles of multiple analysts in the analysis process.\n", + "\n", + "**Do not list more than 5 record ids in a single reference**. Instead, list the top 5 most relevant record ids and add \"+more\" to indicate that there are more.\n", + "\n", + "For example:\n", + "\n", + "\"Person X is the owner of Company Y and subject to many allegations of wrongdoing [Data: Reports (2, 7, 34, 46, 64, +more)]. He is also CEO of company X [Data: Reports (1, 3)]\"\n", + "\n", + "where 1, 2, 3, 7, 34, 46, and 64 represent the id (not the index) of the relevant data record.\n", + "\n", + "Do not include information where the supporting evidence for it is not provided.\n", + "\n", + "\n", + "---Target response length and format---\n", + "\n", + "{response_type}\n", + "\n", + "Add sections and commentary to the response as appropriate for the length and format. Style the response in markdown.\n", + "\"\"\"\n", + "\n", + "reduce_prompt = ChatPromptTemplate.from_messages(\n", + " [\n", + " (\n", + " \"system\",\n", + " REDUCE_SYSTEM_PROMPT,\n", + " ),\n", + " (\n", + " \"human\",\n", + " \"{question}\",\n", + " ),\n", + " ]\n", + ")\n", + "reduce_chain = reduce_prompt | llm | StrOutputParser()" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "graph = Neo4jGraph(\n", + " url=os.environ[\"NEO4J_URI\"],\n", + " username=os.environ[\"NEO4J_USERNAME\"],\n", + " password=os.environ[\"NEO4J_PASSWORD\"],\n", + " refresh_schema=False,\n", + ")\n", + "\n", + "response_type: str = \"multiple paragraphs\"\n", + "\n", + "\n", + "def global_retriever(query: str, level: int, response_type: str = response_type) -> str:\n", + " community_data = graph.query(\n", + " \"\"\"\n", + " MATCH (c:__Community__)\n", + " WHERE c.level = $level\n", + " RETURN c.full_content AS output\n", + " \"\"\",\n", + " params={\"level\": level},\n", + " )\n", + " intermediate_results = []\n", + " for community in tqdm(community_data, desc=\"Processing communities\"):\n", + " intermediate_response = map_chain.invoke(\n", + " {\"question\": query, \"context_data\": community[\"output\"]}\n", + " )\n", + " intermediate_results.append(intermediate_response)\n", + " final_response = reduce_chain.invoke(\n", + " {\n", + " \"report_data\": intermediate_results,\n", + " \"question\": query,\n", + " \"response_type\": response_type,\n", + " }\n", + " )\n", + " return final_response" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING:neo4j.notifications:Received notification from DBMS server: {severity: WARNING} {code: Neo.ClientNotification.Statement.UnknownPropertyKeyWarning} {category: UNRECOGNIZED} {title: The provided property key is not in the database} {description: One of the property names in your query is not available in the database, make sure you didn't misspell it or that the label is available when you run this statement in your application (the missing property name is: full_content)} {position: line: 4, column: 14, offset: 69} for query: '\\n MATCH (c:__Community__)\\n WHERE c.level = $level\\n RETURN c.full_content AS output\\n '\n", + "Processing communities: 0it [00:00, ?it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "I'm sorry, but the provided reports do not contain sufficient information to provide an answer to your question about the major cities of India. If you have any other questions or need information on a different topic, please let me know!\n" + ] + } + ], + "source": [ + "print(global_retriever(\"Major cities of India?\", 2))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "chatbotenv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.13" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From e078e214b4ffe675274ebcc040bbfcb8e4f812d8 Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Tue, 20 Aug 2024 12:29:34 +0000 Subject: [PATCH 003/292] connection _check --- backend/score.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/score.py b/backend/score.py index 10bb52738..4daffbc73 100644 --- a/backend/score.py +++ b/backend/score.py @@ -360,7 +360,7 @@ async def clear_chat_bot(uri=Form(),userName=Form(), password=Form(), database=F async def connect(uri=Form(), userName=Form(), password=Form(), database=Form()): try: graph = create_graph_database_connection(uri, userName, password, database) - result = await asyncio.to_thread(connection_check, graph) + result = await asyncio.to_thread(connection_check_and_get_vector_dimensions, graph) json_obj = {'api_name':'connect','db_url':uri,'status':result, 'count':1, 'logging_time': formatted_time(datetime.now(timezone.utc))} logger.log_struct(json_obj) return create_api_response('Success',message=result) From 7c66bf23fc8ce6a9978645273055bdfaad827460 Mon Sep 17 00:00:00 2001 From: destiny966113 <90891243+destiny966113@users.noreply.github.com> Date: Tue, 20 Aug 2024 18:49:04 +0800 Subject: [PATCH 004/292] Fix typo: correct 'josn_obj' to 'json_obj' (#697) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Staging To Main (#495) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * Dev (#433) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env * DEV to STAGING (#461) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * DEV to STAGING (#462) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * added upload api * changed the dropzone error message * Dev to staging (#466) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env * added upload api * changed the dropzone error message --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * format fixes * Close connect when graph object is not none * Call garbage collector to release the menory * Change error message * Added driver config as user_agent * Updated doc for the LLM_MODELS and GCS_FILE_CACHE (#473) * Web URLs are user input (#475) * web url support backend * added the tabs for input source * user agent added for Neo4jGraph connection * Tab view for sources * extract handling for web ur's * initial input handling * chunk creation before processing * code structure * format fixes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * changed the regex for web and cancel button naming * changed the schema dropdown type * readme updates * PROD version fix * changed the alert message for gcs * Delete unconnected entities from DB (#482) * 457 add schema before generate graph (#478) * schema setting from generate graph * changes * changes * badge changes * bug fix * Fulltext index and Update similarity graph (#479) * added full_text index * added one common function for post_processing * post processing api * added tasks param * modifed logging * post processing changes --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Graph and vector search (#485) * Modified the retrival query * added the chatmode toggle component * Modified to vector search * Moved the templates to constants * added the icons * added chat modes * code structure changes * Intergrated the API changges * Modified retrieval queries,refactored code * API integration changes * added the score * order change * wording change * modified constants * added graph+vector * added the tooltips * Modified query * removed the graph mode * tooltip camel Case * added the icon and extern link for web source in the info modal * added the youtube link in the source used tab * format fixes * added the hoverable link --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Update InfoModal.tsx * removed hover from chunks * removed page number * removed page number * removed pag… * Dev To STAGING (#532) * format fixes and graph schema indication fix * Update README.md * added chat modes variable in env updated the readme * spell fix * added the chat mode in env table * added the logos * fixed the overflow issues * removed the extra fix * Fixed specific scenario "when the text from schema closes it should reopen the previous modal" * readme changes * removed dev console logs * added new retrieval query (#533) * format fixes and tab rendering fix * fixed the setting modal reopen issue --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Dev (#535) * format fixes and graph schema indication fix * Update README.md * added chat modes variable in env updated the readme * spell fix * added the chat mode in env table * added the logos * fixed the overflow issues * removed the extra fix * Fixed specific scenario "when the text from schema closes it should reopen the previous modal" * readme changes * removed dev console logs * added new retrieval query (#533) * format fixes and tab rendering fix * fixed the setting modal reopen issue --------- Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * staging changes to main * Update README.md (#539) * docs: update README.md (#546) specifiy -> specify * Fix typo: correct 'josn_obj' to 'json_obj' --------- Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> Co-authored-by: Ikko Eltociear Ashimine Co-authored-by: Andy --- backend/score.py | 69 +++++++++---------- .../src/components/Graph/GraphViewModal.tsx | 2 +- frontend/src/components/Graph/LegendsChip.tsx | 2 +- frontend/src/components/Layout/PageLayout.tsx | 2 +- .../Popups/DeletePopUp/DeletePopUp.tsx | 2 +- .../DeleteTabForOrphanNodes/index.tsx | 2 +- .../Popups/GraphEnhancementDialog/index.tsx | 2 +- .../Popups/LargeFilePopUp/LargeFilesAlert.tsx | 2 +- frontend/src/components/QuickStarter.tsx | 5 +- 9 files changed, 45 insertions(+), 43 deletions(-) diff --git a/backend/score.py b/backend/score.py index 6f5113db6..10bb52738 100644 --- a/backend/score.py +++ b/backend/score.py @@ -105,8 +105,8 @@ async def create_source_knowledge_graph_url( return create_api_response('Failed',message='source_type is other than accepted source') message = f"Source Node created successfully for source type: {source_type} and source: {source}" - josn_obj = {'api_name':'url_scan','db_url':uri,'url_scanned_file':lst_file_name, 'source_url':source_url, 'wiki_query':wiki_query, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(josn_obj) + json_obj = {'api_name':'url_scan','db_url':uri,'url_scanned_file':lst_file_name, 'source_url':source_url, 'wiki_query':wiki_query, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(json_obj) return create_api_response("Success",message=message,success_count=success_count,failed_count=failed_count,file_name=lst_file_name) except Exception as e: error_message = str(e) @@ -208,9 +208,9 @@ async def extract_knowledge_graph_from_file( else: logging.info(f'Deleted File Path: {merged_file_path} and Deleted File Name : {file_name}') delete_uploaded_local_file(merged_file_path,file_name) - josn_obj = {'message':message,'error_message':error_message, 'file_name': file_name,'status':'Failed','db_url':uri,'failed_count':1, 'source_type': source_type, 'source_url':source_url, 'wiki_query':wiki_query, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(josn_obj) - logging.exception(f'File Failed in extraction: {josn_obj}') + json_obj = {'message':message,'error_message':error_message, 'file_name': file_name,'status':'Failed','db_url':uri,'failed_count':1, 'source_type': source_type, 'source_url':source_url, 'wiki_query':wiki_query, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(json_obj) + logging.exception(f'File Failed in extraction: {json_obj}') return create_api_response('Failed', message=message + error_message[:100], error=error_message, file_name = file_name) finally: gc.collect() @@ -225,8 +225,8 @@ async def get_source_list(uri:str, userName:str, password:str, database:str=None if " " in uri: uri = uri.replace(" ","+") result = await asyncio.to_thread(get_source_list_from_graph,uri,userName,decoded_password,database) - josn_obj = {'api_name':'sources_list','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(josn_obj) + json_obj = {'api_name':'sources_list','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(json_obj) return create_api_response("Success",data=result) except Exception as e: job_status = "Failed" @@ -243,19 +243,18 @@ async def post_processing(uri=Form(), userName=Form(), password=Form(), database if "materialize_text_chunk_similarities" in tasks: await asyncio.to_thread(update_graph, graph) - josn_obj = {'api_name': 'post_processing/materialize_text_chunk_similarities', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(josn_obj) + json_obj = {'api_name': 'post_processing/update_similarity_graph', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(json_obj) logging.info(f'Updated KNN Graph') - if "enable_hybrid_search_and_fulltext_search_in_bloom" in tasks: - await asyncio.to_thread(create_fulltext, uri=uri, username=userName, password=password, database=database,type="entities") - await asyncio.to_thread(create_fulltext, uri=uri, username=userName, password=password, database=database,type="keyword") - josn_obj = {'api_name': 'post_processing/enable_hybrid_search_and_fulltext_search_in_bloom', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(josn_obj) + if "create_fulltext_index" in tasks: + await asyncio.to_thread(create_fulltext, uri=uri, username=userName, password=password, database=database) + json_obj = {'api_name': 'post_processing/create_fulltext_index', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(json_obj) logging.info(f'Full Text index created') if os.environ.get('ENTITY_EMBEDDING','False').upper()=="TRUE" and "materialize_entity_similarities" in tasks: await asyncio.to_thread(create_entity_embedding, graph) - josn_obj = {'api_name': 'post_processing/materialize_entity_similarities', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(josn_obj) + json_obj = {'api_name': 'post_processing/create_entity_embedding', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(json_obj) logging.info(f'Entity Embeddings created') return create_api_response('Success', message='All tasks completed successfully') @@ -284,8 +283,8 @@ async def chat_bot(uri=Form(),model=Form(None),userName=Form(), password=Form(), logging.info(f"Total Response time is {total_call_time:.2f} seconds") result["info"]["response_time"] = round(total_call_time, 2) - josn_obj = {'api_name':'chat_bot','db_url':uri,'session_id':session_id, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(josn_obj) + json_obj = {'api_name':'chat_bot','db_url':uri,'session_id':session_id, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(json_obj) return create_api_response('Success',data=result) except Exception as e: job_status = "Failed" @@ -301,8 +300,8 @@ async def chunk_entities(uri=Form(),userName=Form(), password=Form(), chunk_ids= try: logging.info(f"URI: {uri}, Username: {userName}, chunk_ids: {chunk_ids}") result = await asyncio.to_thread(get_entities_from_chunkids,uri=uri, username=userName, password=password, chunk_ids=chunk_ids) - josn_obj = {'api_name':'chunk_entities','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(josn_obj) + json_obj = {'api_name':'chunk_entities','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(json_obj) return create_api_response('Success',data=result) except Exception as e: job_status = "Failed" @@ -329,8 +328,8 @@ async def graph_query( password=password, document_names=document_names ) - josn_obj = {'api_name':'graph_query','db_url':uri,'document_names':document_names, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(josn_obj) + json_obj = {'api_name':'graph_query','db_url':uri,'document_names':document_names, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(json_obj) return create_api_response('Success', data=result) except Exception as e: job_status = "Failed" @@ -361,10 +360,10 @@ async def clear_chat_bot(uri=Form(),userName=Form(), password=Form(), database=F async def connect(uri=Form(), userName=Form(), password=Form(), database=Form()): try: graph = create_graph_database_connection(uri, userName, password, database) - result = await asyncio.to_thread(connection_check_and_get_vector_dimensions, graph) - josn_obj = {'api_name':'connect','db_url':uri,'status':result, 'count':1, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(josn_obj) - return create_api_response('Success',data=result) + result = await asyncio.to_thread(connection_check, graph) + json_obj = {'api_name':'connect','db_url':uri,'status':result, 'count':1, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(json_obj) + return create_api_response('Success',message=result) except Exception as e: job_status = "Failed" message="Connection failed to connect Neo4j database" @@ -379,8 +378,8 @@ async def upload_large_file_into_chunks(file:UploadFile = File(...), chunkNumber try: graph = create_graph_database_connection(uri, userName, password, database) result = await asyncio.to_thread(upload_file, graph, model, file, chunkNumber, totalChunks, originalname, uri, CHUNK_DIR, MERGED_DIR) - josn_obj = {'api_name':'upload','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(josn_obj) + json_obj = {'api_name':'upload','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(json_obj) if int(chunkNumber) == int(totalChunks): return create_api_response('Success',data=result, message='Source Node Created Successfully') else: @@ -401,8 +400,8 @@ async def get_structured_schema(uri=Form(), userName=Form(), password=Form(), da graph = create_graph_database_connection(uri, userName, password, database) result = await asyncio.to_thread(get_labels_and_relationtypes, graph) logging.info(f'Schema result from DB: {result}') - josn_obj = {'api_name':'schema','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(josn_obj) + json_obj = {'api_name':'schema','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(json_obj) return create_api_response('Success', data=result) except Exception as e: message="Unable to get the labels and relationtypes from neo4j database" @@ -468,10 +467,10 @@ async def delete_document_and_entities(uri=Form(), graph = create_graph_database_connection(uri, userName, password, database) graphDb_data_Access = graphDBdataAccess(graph) result, files_list_size = await asyncio.to_thread(graphDb_data_Access.delete_file_from_graph, filenames, source_types, deleteEntities, MERGED_DIR, uri) - # entities_count = result[0]['deletedEntities'] if 'deletedEntities' in result[0] else 0 - message = f"Deleted {files_list_size} documents with entities from database" - josn_obj = {'api_name':'delete_document_and_entities','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(josn_obj) + entities_count = result[0]['deletedEntities'] if 'deletedEntities' in result[0] else 0 + message = f"Deleted {files_list_size} documents with {entities_count} entities from database" + json_obj = {'api_name':'delete_document_and_entities','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(json_obj) return create_api_response('Success',message=message) except Exception as e: job_status = "Failed" @@ -627,4 +626,4 @@ async def merge_duplicate_nodes(uri=Form(), userName=Form(), password=Form(), da gc.collect() if __name__ == "__main__": - uvicorn.run(app) \ No newline at end of file + uvicorn.run(app) diff --git a/frontend/src/components/Graph/GraphViewModal.tsx b/frontend/src/components/Graph/GraphViewModal.tsx index 9c0d5d190..5479509a1 100644 --- a/frontend/src/components/Graph/GraphViewModal.tsx +++ b/frontend/src/components/Graph/GraphViewModal.tsx @@ -356,4 +356,4 @@ const GraphViewModal: React.FunctionComponent = ({ ); }; -export default GraphViewModal; +export default GraphViewModal; \ No newline at end of file diff --git a/frontend/src/components/Graph/LegendsChip.tsx b/frontend/src/components/Graph/LegendsChip.tsx index 7e121dc67..7d2de8b74 100644 --- a/frontend/src/components/Graph/LegendsChip.tsx +++ b/frontend/src/components/Graph/LegendsChip.tsx @@ -5,7 +5,7 @@ import Legend from '../UI/Legend'; export const LegendsChip: React.FunctionComponent = ({ scheme, title, nodes }) => { const chunkcount = useMemo( () => [...new Set(nodes?.filter((n) => n?.labels?.includes(title)).map((i) => i.id))].length, - [nodes] + [] ); return ; diff --git a/frontend/src/components/Layout/PageLayout.tsx b/frontend/src/components/Layout/PageLayout.tsx index 8aca58109..1a2f755b4 100644 --- a/frontend/src/components/Layout/PageLayout.tsx +++ b/frontend/src/components/Layout/PageLayout.tsx @@ -175,4 +175,4 @@ export default function PageLayoutNew({ /> ); -} +} \ No newline at end of file diff --git a/frontend/src/components/Popups/DeletePopUp/DeletePopUp.tsx b/frontend/src/components/Popups/DeletePopUp/DeletePopUp.tsx index 1b1bd58c8..eb1522868 100644 --- a/frontend/src/components/Popups/DeletePopUp/DeletePopUp.tsx +++ b/frontend/src/components/Popups/DeletePopUp/DeletePopUp.tsx @@ -54,4 +54,4 @@ export default function DeletePopUp({ ); -} +} \ No newline at end of file diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx index 2dc8a13ff..9cdf239dc 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx @@ -279,4 +279,4 @@ export default function DeletePopUpForOrphanNodes({ ); -} +} \ No newline at end of file diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/index.tsx index 84577c53c..5e2aaf713 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/index.tsx @@ -126,4 +126,4 @@ export default function GraphEnhancementDialog({ ); -} +} \ No newline at end of file diff --git a/frontend/src/components/Popups/LargeFilePopUp/LargeFilesAlert.tsx b/frontend/src/components/Popups/LargeFilePopUp/LargeFilesAlert.tsx index 26c9cfcda..b2eb01a52 100644 --- a/frontend/src/components/Popups/LargeFilePopUp/LargeFilesAlert.tsx +++ b/frontend/src/components/Popups/LargeFilePopUp/LargeFilesAlert.tsx @@ -100,4 +100,4 @@ const LargeFilesAlert: FC = ({ largeFiles, handleToggle, checke ); }; -export default LargeFilesAlert; +export default LargeFilesAlert; \ No newline at end of file diff --git a/frontend/src/components/QuickStarter.tsx b/frontend/src/components/QuickStarter.tsx index db2cba7e7..bfbbaf55b 100644 --- a/frontend/src/components/QuickStarter.tsx +++ b/frontend/src/components/QuickStarter.tsx @@ -11,6 +11,7 @@ const QuickStarter: React.FunctionComponent = () => { const themeUtils = React.useContext(ThemeWrapperContext); const [themeMode, setThemeMode] = useState(themeUtils.colorMode); const [showSettingsModal, setshowSettingsModal] = useState(false); + const [showOrphanNodeDeletionDialog, setshowOrphanNodeDeletionDialog] = useState(false); const toggleColorMode = () => { setThemeMode((prevThemeMode) => { @@ -24,7 +25,6 @@ const QuickStarter: React.FunctionComponent = () => { const closeSettingModal = () => { setshowSettingsModal(false); }; - return ( @@ -35,6 +35,9 @@ const QuickStarter: React.FunctionComponent = () => { openSettingsDialog={openSettingsModal} isSettingPanelExpanded={showSettingsModal} closeSettingModal={closeSettingModal} + closeOrphanNodeDeletionModal={closeOrphanNodeDeletionModal} + showOrphanNodeDeletionModal={showOrphanNodeDeletionDialog} + openOrphanNodeDeletionModal={openOrphanNodeDeletionModal} /> From 477fda0bcfe5ed56edc7cd4e738ce63f0d74c691 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Tue, 20 Aug 2024 11:57:15 +0000 Subject: [PATCH 005/292] lint fixes --- frontend/src/components/QuickStarter.tsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/QuickStarter.tsx b/frontend/src/components/QuickStarter.tsx index bfbbaf55b..29832fee1 100644 --- a/frontend/src/components/QuickStarter.tsx +++ b/frontend/src/components/QuickStarter.tsx @@ -11,7 +11,6 @@ const QuickStarter: React.FunctionComponent = () => { const themeUtils = React.useContext(ThemeWrapperContext); const [themeMode, setThemeMode] = useState(themeUtils.colorMode); const [showSettingsModal, setshowSettingsModal] = useState(false); - const [showOrphanNodeDeletionDialog, setshowOrphanNodeDeletionDialog] = useState(false); const toggleColorMode = () => { setThemeMode((prevThemeMode) => { @@ -25,6 +24,7 @@ const QuickStarter: React.FunctionComponent = () => { const closeSettingModal = () => { setshowSettingsModal(false); }; + return ( @@ -35,9 +35,6 @@ const QuickStarter: React.FunctionComponent = () => { openSettingsDialog={openSettingsModal} isSettingPanelExpanded={showSettingsModal} closeSettingModal={closeSettingModal} - closeOrphanNodeDeletionModal={closeOrphanNodeDeletionModal} - showOrphanNodeDeletionModal={showOrphanNodeDeletionDialog} - openOrphanNodeDeletionModal={openOrphanNodeDeletionModal} /> @@ -45,4 +42,4 @@ const QuickStarter: React.FunctionComponent = () => { ); }; -export default QuickStarter; +export default QuickStarter; \ No newline at end of file From bacbcfc202c1718a72306c37bff71d19d26be701 Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Tue, 20 Aug 2024 12:29:34 +0000 Subject: [PATCH 006/292] connection _check --- backend/score.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/score.py b/backend/score.py index 10bb52738..4daffbc73 100644 --- a/backend/score.py +++ b/backend/score.py @@ -360,7 +360,7 @@ async def clear_chat_bot(uri=Form(),userName=Form(), password=Form(), database=F async def connect(uri=Form(), userName=Form(), password=Form(), database=Form()): try: graph = create_graph_database_connection(uri, userName, password, database) - result = await asyncio.to_thread(connection_check, graph) + result = await asyncio.to_thread(connection_check_and_get_vector_dimensions, graph) json_obj = {'api_name':'connect','db_url':uri,'status':result, 'count':1, 'logging_time': formatted_time(datetime.now(timezone.utc))} logger.log_struct(json_obj) return create_api_response('Success',message=result) From 8e14771bf9d61effd65d85909d7c4b602d0d68e2 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Tue, 20 Aug 2024 14:59:04 +0000 Subject: [PATCH 007/292] removed tqdm --- backend/src/communities.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/communities.py b/backend/src/communities.py index e2f09cba6..b795ae4ed 100644 --- a/backend/src/communities.py +++ b/backend/src/communities.py @@ -198,7 +198,7 @@ def create_community_summaries(graph, model): with ThreadPoolExecutor() as executor: futures = {executor.submit(process_community, community, community_chain): community for community in community_info_list} - for future in tqdm(as_completed(futures), total=len(futures), desc="Processing communities"): + for future in as_completed(futures): try: summaries.append(future.result()) except Exception as e: From 2fc3e136df024bac3a13b90705c952983c1d2046 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Wed, 21 Aug 2024 13:06:42 +0530 Subject: [PATCH 008/292] Chatbot changes (#700) * added Hybrid search from graph * modified mode params --- backend/requirements.txt | 2 +- backend/score.py | 10 ++++++---- backend/src/QA_integration_new.py | 26 +++++++++++++------------- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/backend/requirements.txt b/backend/requirements.txt index ab42a749d..0c903a325 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -74,7 +74,7 @@ langchain-aws==0.1.9 langchain-anthropic==0.1.19 langchain-fireworks==0.1.4 langchain-google-genai==1.0.7 -langchain-community==0.2.7 +langchain-community==0.2.12 langchain-core==0.2.19 langchain-experimental==0.0.62 langchain-google-vertexai==1.0.6 diff --git a/backend/score.py b/backend/score.py index 3e6512a38..0b63e57d4 100644 --- a/backend/score.py +++ b/backend/score.py @@ -246,10 +246,12 @@ async def post_processing(uri=Form(), userName=Form(), password=Form(), database json_obj = {'api_name': 'post_processing/update_similarity_graph', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} logger.log_struct(json_obj) logging.info(f'Updated KNN Graph') - if "create_fulltext_index" in tasks: - await asyncio.to_thread(create_fulltext, uri=uri, username=userName, password=password, database=database) - json_obj = {'api_name': 'post_processing/create_fulltext_index', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(json_obj) + + if "enable_hybrid_search_and_fulltext_search_in_bloom" in tasks: + await asyncio.to_thread(create_fulltext, uri=uri, username=userName, password=password, database=database,type="entities") + # await asyncio.to_thread(create_fulltext, uri=uri, username=userName, password=password, database=database,type="keyword") + josn_obj = {'api_name': 'post_processing/enable_hybrid_search_and_fulltext_search_in_bloom', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(josn_obj) logging.info(f'Full Text index created') if os.environ.get('ENTITY_EMBEDDING','False').upper()=="TRUE" and "materialize_entity_similarities" in tasks: await asyncio.to_thread(create_entity_embedding, graph) diff --git a/backend/src/QA_integration_new.py b/backend/src/QA_integration_new.py index 1c0bc254c..5a2baa599 100644 --- a/backend/src/QA_integration_new.py +++ b/backend/src/QA_integration_new.py @@ -41,26 +41,26 @@ def get_neo4j_retriever(graph, retrieval_query,document_names,mode,index_name="vector",keyword_index="keyword", search_k=CHAT_SEARCH_KWARG_K, score_threshold=CHAT_SEARCH_KWARG_SCORE_THRESHOLD): try: - if mode == "hybrid": - # neo_db = Neo4jVector.from_existing_graph( - # embedding=EMBEDDING_FUNCTION, - # index_name=index_name, - # retrieval_query=retrieval_query, - # graph=graph, - # search_type="hybrid", - # node_label="Chunk", - # embedding_node_property="embedding", - # text_node_properties=["text"] - # # keyword_index_name=keyword_index - # ) - neo_db = Neo4jVector.from_existing_index( + if mode == "hybrid" or mode == "hybrid+graph": + neo_db = Neo4jVector.from_existing_graph( embedding=EMBEDDING_FUNCTION, index_name=index_name, retrieval_query=retrieval_query, graph=graph, search_type="hybrid", + node_label="Chunk", + embedding_node_property="embedding", + text_node_properties=["text"], keyword_index_name=keyword_index ) + # neo_db = Neo4jVector.from_existing_index( + # embedding=EMBEDDING_FUNCTION, + # index_name=index_name, + # retrieval_query=retrieval_query, + # graph=graph, + # search_type="hybrid", + # keyword_index_name=keyword_index + # ) logging.info(f"Successfully retrieved Neo4jVector index '{index_name}' and keyword index '{keyword_index}'") else: neo_db = Neo4jVector.from_existing_index( From 279d820dfb8b156797f5798e1791cef6483da75e Mon Sep 17 00:00:00 2001 From: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Date: Wed, 21 Aug 2024 09:54:24 +0000 Subject: [PATCH 009/292] fixed issue delete entities return count --- backend/score.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/score.py b/backend/score.py index 0b63e57d4..00650b56e 100644 --- a/backend/score.py +++ b/backend/score.py @@ -469,8 +469,8 @@ async def delete_document_and_entities(uri=Form(), graph = create_graph_database_connection(uri, userName, password, database) graphDb_data_Access = graphDBdataAccess(graph) result, files_list_size = await asyncio.to_thread(graphDb_data_Access.delete_file_from_graph, filenames, source_types, deleteEntities, MERGED_DIR, uri) - entities_count = result[0]['deletedEntities'] if 'deletedEntities' in result[0] else 0 - message = f"Deleted {files_list_size} documents with {entities_count} entities from database" + # entities_count = result[0]['deletedEntities'] if 'deletedEntities' in result[0] else 0 + message = f"Deleted {files_list_size} documents with entities from database" json_obj = {'api_name':'delete_document_and_entities','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} logger.log_struct(json_obj) return create_api_response('Success',message=message) From 30f92cd5114088a3be5d6e85f4a11d2797b2db78 Mon Sep 17 00:00:00 2001 From: Pravesh1988 Date: Wed, 21 Aug 2024 10:00:08 +0000 Subject: [PATCH 010/292] removed specified version due to dependency clashes between versions --- backend/requirements.txt | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/backend/requirements.txt b/backend/requirements.txt index 0c903a325..46c57aea5 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -69,18 +69,18 @@ jsonpath-python==1.0.6 jsonpointer==2.4 json-repair==0.25.2 kiwisolver==1.4.5 -langchain==0.2.8 -langchain-aws==0.1.9 -langchain-anthropic==0.1.19 -langchain-fireworks==0.1.4 -langchain-google-genai==1.0.7 -langchain-community==0.2.12 -langchain-core==0.2.19 -langchain-experimental==0.0.62 -langchain-google-vertexai==1.0.6 -langchain-groq==0.1.6 -langchain-openai==0.1.14 -langchain-text-splitters==0.2.2 +langchain +langchain-aws +langchain-anthropic +langchain-fireworks +langchain-google-genai +langchain-community +langchain-core +langchain-experimental +langchain-google-vertexai +langchain-groq +langchain-openai +langchain-text-splitters langdetect==1.0.9 langsmith==0.1.83 layoutparser==0.3.4 From edcff3bb931c865392c9931a4b07b477dbc702f6 Mon Sep 17 00:00:00 2001 From: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Date: Wed, 21 Aug 2024 10:34:20 +0000 Subject: [PATCH 011/292] updated script"integration test cases" --- backend/test_integrationqa.py | 368 +++++++++++++--------------------- 1 file changed, 135 insertions(+), 233 deletions(-) diff --git a/backend/test_integrationqa.py b/backend/test_integrationqa.py index cd662cbdc..20f3effb0 100644 --- a/backend/test_integrationqa.py +++ b/backend/test_integrationqa.py @@ -1,270 +1,172 @@ +import os +import shutil +import logging +import pandas as pd +from datetime import datetime as dt +from dotenv import load_dotenv + from score import * from src.main import * -import logging from src.QA_integration_new import QA_RAG from langserve import add_routes -import asyncio -import os -from dotenv import load_dotenv -import pandas as pd -from datetime import datetime as dt -uri = '' -userName = '' -password = '' -# model = 'openai-gpt-3.5' -database = 'neo4j' +# Load environment variables if needed +load_dotenv() + +# Constants +URI = '' +USERNAME = '' +PASSWORD = '' +DATABASE = 'neo4j' CHUNK_DIR = os.path.join(os.path.dirname(__file__), "chunks") MERGED_DIR = os.path.join(os.path.dirname(__file__), "merged_files") -graph = create_graph_database_connection(uri, userName, password, database) - - -def test_graph_from_file_local_file(model_name): - model = model_name - file_name = 'About Amazon.pdf' - # shutil.copyfile('data/Bank of America Q23.pdf', 'backend/src/merged_files/Bank of America Q23.pdf') - shutil.copyfile('/workspaces/llm-graph-builder/backend/files/About Amazon.pdf', - '/workspaces/llm-graph-builder/backend/merged_files/About Amazon.pdf') - obj_source_node = sourceNode() - obj_source_node.file_name = file_name - obj_source_node.file_type = 'pdf' - obj_source_node.file_size = '1087' - obj_source_node.file_source = 'local file' - obj_source_node.model = model - obj_source_node.created_at = datetime.now() - graphDb_data_Access = graphDBdataAccess(graph) - graphDb_data_Access.create_source_node(obj_source_node) - merged_file_path = os.path.join(MERGED_DIR, file_name) - print(merged_file_path) - - local_file_result = extract_graph_from_file_local_file(uri, userName, password, database, model, merged_file_path, file_name, '', '') - # final_list.append(local_file_result) - print(local_file_result) +# Initialize database connection +graph = create_graph_database_connection(URI, USERNAME, PASSWORD, DATABASE) + +def create_source_node_local(graph, model, file_name): + """Creates a source node for a local file.""" + source_node = sourceNode() + source_node.file_name = file_name + source_node.file_type = 'pdf' + source_node.file_size = '1087' + source_node.file_source = 'local file' + source_node.model = model + source_node.created_at = dt.now() + graphDB_data_Access = graphDBdataAccess(graph) + graphDB_data_Access.create_source_node(source_node) + return source_node + +def test_graph_from_file_local(model_name): + """Test graph creation from a local file.""" + file_name = 'About Amazon.pdf' + shutil.copyfile('/workspaces/llm-graph-builder/backend/files/About Amazon.pdf', + os.path.join(MERGED_DIR, file_name)) + + create_source_node_local(graph, model_name, file_name) + merged_file_path = os.path.join(MERGED_DIR, file_name) + + local_file_result = extract_graph_from_file_local_file( + URI, USERNAME, PASSWORD, DATABASE, model_name, merged_file_path, file_name, '', '' + ) + logging.info("Local file processing complete") + print(local_file_result) - logging.info("Info: ") - try: - assert local_file_result['status'] == 'Completed' and local_file_result['nodeCount'] > 0 and local_file_result[ - 'relationshipCount'] > 0 - return local_file_result - print("Success") - except AssertionError as e: - print("Fail: ", e) - return local_file_result - - -def test_graph_from_file_local_file_failed(model_name): - model = model_name - file_name = 'Not_exist.pdf' - try: - obj_source_node = sourceNode() - obj_source_node.file_name = file_name - obj_source_node.file_type = 'pdf' - obj_source_node.file_size = '0' - obj_source_node.file_source = 'local file' - obj_source_node.model = model - obj_source_node.created_at = datetime.now() - graphDb_data_Access = graphDBdataAccess(graph) - graphDb_data_Access.create_source_node(obj_source_node) - - local_file_result = extract_graph_from_file_local_file(graph, model, file_name, merged_file_path, '', '') + try: + assert local_file_result['status'] == 'Completed' + assert local_file_result['nodeCount'] > 0 + assert local_file_result['relationshipCount'] > 0 + print("Success") + except AssertionError as e: + print("Fail: ", e) - print(local_file_result) - except AssertionError as e: - print('Failed due to file does not exist means not uploaded or accidentaly deleteled from server') - print("Failed: Error from extract function ", e) + return local_file_result -# Check for Wikipedia file to be test -def test_graph_from_Wikipedia(model_name): - model = model_name +def test_graph_from_wikipedia(model_name): + """Test graph creation from a Wikipedia page.""" wiki_query = 'https://en.wikipedia.org/wiki/Ram_Mandir' source_type = 'Wikipedia' file_name = "Ram_Mandir" - create_source_node_graph_url_wikipedia(graph, model, wiki_query, source_type) - wikiresult = extract_graph_from_file_Wikipedia(uri, userName, password, database, model, file_name, 1, 'en', '', '') - logging.info("Info: Wikipedia test done") - print(wikiresult) - + create_source_node_graph_url_wikipedia(graph, model_name, wiki_query, source_type) + + wiki_result = extract_graph_from_file_Wikipedia( + URI, USERNAME, PASSWORD, DATABASE, model_name, file_name, 1, 'en', '', '' + ) + logging.info("Wikipedia test done") + print(wiki_result) + try: - assert wikiresult['status'] == 'Completed' and wikiresult['nodeCount'] > 0 and wikiresult['relationshipCount'] > 0 - return wikiresult + assert wiki_result['status'] == 'Completed' + assert wiki_result['nodeCount'] > 0 + assert wiki_result['relationshipCount'] > 0 print("Success") except AssertionError as e: - print("Fail ", e) - return wikiresult + print("Fail: ", e) + return wiki_result -def test_graph_from_Wikipedia_failed(): - wiki_query = 'Test QA 123456' - source_type = 'Wikipedia' - try: - logging.info("Created source node for wikipedia") - create_source_node_graph_url_wikipedia(graph, model, wiki_query, source_type) - except AssertionError as e: - print("Fail ", e) - -# Check for Youtube_video to be Success def test_graph_from_youtube_video(model_name): - model = model_name + """Test graph creation from a YouTube video.""" source_url = 'https://www.youtube.com/watch?v=T-qy-zPWgqA' source_type = 'youtube' - create_source_node_graph_url_youtube(graph, model, source_url, source_type) - youtuberesult = extract_graph_from_file_youtube(uri, userName, password, database, model, source_url, '', '') + create_source_node_graph_url_youtube(graph, model_name, source_url, source_type) + youtube_result = extract_graph_from_file_youtube( + URI, USERNAME, PASSWORD, DATABASE, model_name, source_url, '', '' + ) + logging.info("YouTube Video test done") + print(youtube_result) - logging.info("Info: Youtube Video test done") - print(youtuberesult) try: - assert youtuberesult['status'] == 'Completed' and youtuberesult['nodeCount'] > 1 and youtuberesult[ - 'relationshipCount'] > 1 - return youtuberesult + assert youtube_result['status'] == 'Completed' + assert youtube_result['nodeCount'] > 1 + assert youtube_result['relationshipCount'] > 1 print("Success") except AssertionError as e: - print("Failed ", e) - return youtuberesult - -# Check for Youtube_video to be Failed - -def test_graph_from_youtube_video_failed(): - url = 'https://www.youtube.com/watch?v=U9mJuUkhUzk' - source_type = 'youtube' - - create_source_node_graph_url_youtube(graph, model, url, source_type) - youtuberesult = extract_graph_from_file_youtube(graph, model, url, ',', ',') - # print(result) - print(youtuberesult) - try: - assert youtuberesult['status'] == 'Completed' - return youtuberesult - except AssertionError as e: - print("Failed ", e) - - -# Check for the GCS file to be uploaded, process and completed - -def test_graph_from_file_test_gcs(): - bucket_name = 'test' - folder_name = 'test' - source_type = 'gcs test bucket' - file_name = 'Neuralink brain chip patient playing chess.pdf' - create_source_node_graph_url_gcs(graph, model, bucket_name, folder_name, source_type) - gcsresult = extract_graph_from_file_gcs(graph, model, bucket_name, folder_name, file_name, '', '') + print("Failed: ", e) - logging.info("Info") - print(gcsresult) - - try: - assert gcsresult['status'] == 'Completed' and gcsresult['nodeCount'] > 10 and gcsresult['relationshipCount'] > 5 - print("Success") - except AssertionError as e: - print("Failed ", e) - - -def test_graph_from_file_test_gcs_failed(): - bucket_name = 'llm_graph_test' - folder_name = 'test' - source_type = 'gcs bucket' - # file_name = 'Neuralink brain chip patient playing chess.pdf' - try: - create_source_node_graph_url_gcs(graph, model, bucket_name, folder_name, source_type) - print("GCS: Create source node failed due to bucket not exist") - except AssertionError as e: - print("Failed ", e) - - -def test_graph_from_file_test_s3_failed(): - source_url = 's3://development-llm-test/' - try: - create_source_node_graph_url_s3(graph, model, source_url, 'test123', 'pwd123') - # assert result['status'] == 'Failed' - # print("S3 created source node failed die to wrong access key id and secret") - except AssertionError as e: - print("Failed ", e) - - -# Check the Functionality of Chatbot QnA for mode 'graph+vector' -def test_chatbot_QnA(model_name): - model = model_name - QA_n_RAG = QA_RAG(graph, model, 'Tell me about amazon', '[]', 1, 'graph+vector') + return youtube_result +def test_chatbot_qna(model_name, mode='graph+vector'): + """Test chatbot QnA functionality for different modes.""" + QA_n_RAG = QA_RAG(graph, model_name, 'Tell me about amazon', '[]', 1, mode) print(QA_n_RAG) print(len(QA_n_RAG['message'])) - try: - assert len(QA_n_RAG['message']) > 20 - return QA_n_RAG - print("Success") - except AssertionError as e: - print("Failed ", e) - return QA_n_RAG - -# Check the Functionality of Chatbot QnA for mode 'vector' -def test_chatbot_QnA_vector(model_name): - model = model_name - QA_n_RAG_vector = QA_RAG(graph, model, 'Tell me about amazon', '[]', 1, 'vector') - - - print(QA_n_RAG_vector) - print(len(QA_n_RAG_vector['message'])) try: - assert len(QA_n_RAG_vector['message']) > 20 - return QA_n_RAG_vector - print("Success") - except AssertionError as e: - print("Failed ", e) - return QA_n_RAG_vector - -# Check the Functionality of Chatbot QnA for mode 'hybrid' - -def test_chatbot_QnA_hybrid(model_name): - model = model_name - QA_n_RAG_hybrid = QA_RAG(graph, model, 'Tell me about amazon', '[]', 1, 'hybrid') - - - print(QA_n_RAG_hybrid) - print(len(QA_n_RAG_hybrid['message'])) - try: - assert len(QA_n_RAG_hybrid['message']) > 20 - return QA_n_RAG_hybrid + assert len(QA_n_RAG['message']) > 20 print("Success") except AssertionError as e: - print("Failed ", e) - return QA_n_RAG_hybrid - - + print("Failed: ", e) + + return QA_n_RAG + +def compare_graph_results(results): + """ + Compare graph results across different models. + Add custom logic here to compare graph data, nodes, and relationships. + """ + # Placeholder logic for comparison + print("Comparing results...") + for i in range(len(results) - 1): + result_a = results[i] + result_b = results[i + 1] + if result_a == result_b: + print(f"Result {i} is identical to result {i+1}") + else: + print(f"Result {i} differs from result {i+1}") + +def run_tests(): + final_list = [] + error_list = [] + models = [ + 'openai-gpt-3.5', 'openai-gpt-4o', 'openai-gpt-4o-mini', 'azure_ai_gpt_35', + 'azure_ai_gpt_4o', 'anthropic_claude_3_5_sonnet', 'fireworks_v3p1_405b', + 'fireworks_llama_v3_70b', 'ollama_llama3', 'bedrock_claude_3_5_sonnet' + ] + + for model_name in models: + try: + final_list.append(test_graph_from_file_local(model_name)) + final_list.append(test_graph_from_wikipedia(model_name)) + final_list.append(test_graph_from_youtube_video(model_name)) + final_list.append(test_chatbot_qna(model_name)) + final_list.append(test_chatbot_qna(model_name, mode='vector')) + final_list.append(test_chatbot_qna(model_name, mode='hybrid')) + except Exception as e: + error_list.append((model_name, str(e))) + #Compare and log diffrences in graph results + compare_graph_results(final_list) # Pass the final_list to comapre_graph_results + + # Save final results to CSV + df = pd.DataFrame(final_list) + df['execution_date'] = dt.today().strftime('%Y-%m-%d') + df.to_csv(f"Integration_TestResult_{dt.now().strftime('%Y%m%d_%H%M%S')}.csv", index=False) + + # Save error details to CSV + df_errors = pd.DataFrame(error_list, columns=['Model', 'Error']) + df_errors['execution_date'] = dt.today().strftime('%Y-%m-%d') + df_errors.to_csv(f"Error_details_{dt.now().strftime('%Y%m%d_%H%M%S')}.csv", index=False) if __name__ == "__main__": - final_list = [] - for model_name in ['openai-gpt-3.5','azure_ai_gpt_35','azure_ai_gpt_4o','anthropic_claude_3_5_sonnet','fireworks_llama_v3_70b','bedrock_claude_3_5_sonnet']: - - # local file - response = test_graph_from_file_local_file(model_name) - final_list.append(response) - - # # Wikipedia Test - response = test_graph_from_Wikipedia(model_name) - final_list.append(response) - - # # Youtube Test - response= test_graph_from_youtube_video(model_name) - final_list.append(response) - # # print(final_list) - - # # test_graph_from_file_test_gcs(model_name) # GCS Test - - # #chatbot 'graph+vector' - response = test_chatbot_QnA(model_name) - final_list.append(response) - - # #chatbot 'vector' - response = test_chatbot_QnA_vector(model_name) - final_list.append(response) - - # #chatbot 'hybrid' - response = test_chatbot_QnA_hybrid(model_name) - final_list.append(response) - - # test_graph_from_file_test_s3_failed() # S3 Failed Test Case - df = pd.DataFrame(final_list) - df['execution_date']= datetime.today().strftime('%Y-%m-%d') - df.to_csv(f"Integration_TestResult_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv", index=False) \ No newline at end of file + run_tests() \ No newline at end of file From 71ed29abb32f83095d0e2cbbe1c22d254ed9bc5b Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Wed, 21 Aug 2024 10:54:49 +0000 Subject: [PATCH 012/292] decreased the delay for pollintg API --- frontend/src/services/PollingAPI.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/services/PollingAPI.ts b/frontend/src/services/PollingAPI.ts index 08e6a11bb..baa2e6080 100644 --- a/frontend/src/services/PollingAPI.ts +++ b/frontend/src/services/PollingAPI.ts @@ -15,7 +15,7 @@ export default async function subscribe( const MAX_POLLING_ATTEMPTS = 10; let pollingAttempts = 0; - let delay = 2000; + let delay = 1000; while (pollingAttempts < MAX_POLLING_ATTEMPTS) { let currentdelay = delay; From 1af58770727f65054edc0477aebed91cf142206e Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Wed, 21 Aug 2024 17:27:54 +0530 Subject: [PATCH 013/292] Graph enhancements (#696) * relationship Changes * addition of relationship labels * onclick to nodes * node-highlight * Build fixex * slash docker change * deactivating previous node/relationshsips * lint fixes * class issue * search * search on basis of id / captions * debounce changes * class changes (#693) * legends highlight * search query reset * node size --- frontend/src/App.css | 11 +- .../src/components/ChatBot/ChatInfoModal.tsx | 13 +- .../src/components/ChatBot/Info/InfoModal.tsx | 13 +- .../src/components/Graph/GraphViewModal.tsx | 294 +++++++++++++++--- frontend/src/components/Graph/LegendsChip.tsx | 16 +- .../Deduplication/index.tsx | 6 +- .../DeleteTabForOrphanNodes/index.tsx | 2 +- frontend/src/components/UI/Legend.tsx | 14 +- frontend/src/components/UI/ShowAll.tsx | 38 +++ frontend/src/types.ts | 39 +-- frontend/src/utils/Constants.ts | 4 + frontend/src/utils/Utils.ts | 10 +- frontend/yarn.lock | 2 +- 13 files changed, 363 insertions(+), 99 deletions(-) create mode 100644 frontend/src/components/UI/ShowAll.tsx diff --git a/frontend/src/App.css b/frontend/src/App.css index ff084ffae..fe285c972 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -233,10 +233,8 @@ letter-spacing: 0; line-height: 1.25rem; width: max-content; - height: 30px; text-overflow: ellipsis; white-space: nowrap; - overflow: hidden; } .ndl-widget-content>div { @@ -365,4 +363,13 @@ .widthunset{ width: initial !important; height: initial !important; +} + +.text-input-container { + transition: width 1.5s ease; + /* width: 100dvh; */ +} + +.text-input-container.search-initiated { + width: 60dvh; } \ No newline at end of file diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index 7bd837299..42dad1893 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -18,13 +18,20 @@ import wikipedialogo from '../../assets/images/wikipedia.svg'; import youtubelogo from '../../assets/images/youtube.svg'; import gcslogo from '../../assets/images/gcs.webp'; import s3logo from '../../assets/images/s3logo.png'; -import { Chunk, Entity, ExtendedNode, GroupedEntity, UserCredentials, chatInfoMessage } from '../../types'; +import { + Chunk, + Entity, + ExtendedNode, + ExtendedRelationship, + GroupedEntity, + UserCredentials, + chatInfoMessage, +} from '../../types'; import { useContext, useEffect, useMemo, useState } from 'react'; import HoverableLink from '../UI/HoverableLink'; import GraphViewButton from '../Graph/GraphViewButton'; import { chunkEntitiesAPI } from '../../services/ChunkEntitiesInfo'; import { useCredentials } from '../../context/UserCredentials'; -import type { Relationship } from '@neo4j-nvl/base'; import { calcWordColor } from '@neo4j-devtools/word-color'; import ReactMarkdown from 'react-markdown'; import { GlobeAltIconOutline } from '@neo4j-ndl/react/icons'; @@ -51,7 +58,7 @@ const ChatInfoModal: React.FC = ({ const [loading, setLoading] = useState(false); const { userCredentials } = useCredentials(); const [nodes, setNodes] = useState([]); - const [relationships, setRelationships] = useState([]); + const [relationships, setRelationships] = useState([]); const [chunks, setChunks] = useState([]); const themeUtils = useContext(ThemeWrapperContext); const [, copy] = useCopyToClipboard(); diff --git a/frontend/src/components/ChatBot/Info/InfoModal.tsx b/frontend/src/components/ChatBot/Info/InfoModal.tsx index 0dd325731..cf1bbca47 100644 --- a/frontend/src/components/ChatBot/Info/InfoModal.tsx +++ b/frontend/src/components/ChatBot/Info/InfoModal.tsx @@ -6,13 +6,20 @@ import wikipedialogo from '../../../assets/images/Wikipedia-logo-v2.svg'; import youtubelogo from '../../../assets/images/youtube.png'; import gcslogo from '../../../assets/images/gcs.webp'; import s3logo from '../../../assets/images/s3logo.png'; -import { Chunk, Entity, ExtendedNode, GroupedEntity, UserCredentials, chatInfoMessage } from '../../../types'; +import { + Chunk, + Entity, + ExtendedNode, + ExtendedRelationship, + GroupedEntity, + UserCredentials, + chatInfoMessage, +} from '../../../types'; import { useEffect, useMemo, useState } from 'react'; import HoverableLink from '../../UI/HoverableLink'; import GraphViewButton from '../../Graph/GraphViewButton'; import { chunkEntitiesAPI } from '../../../services/ChunkEntitiesInfo'; import { useCredentials } from '../../../context/UserCredentials'; -import type { Relationship } from '@neo4j-nvl/base'; import { calcWordColor } from '@neo4j-devtools/word-color'; import ReactMarkdown from 'react-markdown'; import { GlobeAltIconOutline } from '@neo4j-ndl/react/icons'; @@ -23,7 +30,7 @@ const InfoModal: React.FC = ({ sources, model, total_tokens, re const [loading, setLoading] = useState(false); const { userCredentials } = useCredentials(); const [nodes, setNodes] = useState([]); - const [relationships, setRelationships] = useState([]); + const [relationships, setRelationships] = useState([]); const [chunks, setChunks] = useState([]); const parseEntity = (entity: Entity) => { const { labels, properties } = entity; diff --git a/frontend/src/components/Graph/GraphViewModal.tsx b/frontend/src/components/Graph/GraphViewModal.tsx index 5479509a1..ca407b4bb 100644 --- a/frontend/src/components/Graph/GraphViewModal.tsx +++ b/frontend/src/components/Graph/GraphViewModal.tsx @@ -1,6 +1,23 @@ -import { Banner, Dialog, Flex, IconButtonArray, LoadingSpinner, Typography } from '@neo4j-ndl/react'; +import { + Banner, + Dialog, + Flex, + IconButton, + IconButtonArray, + LoadingSpinner, + TextInput, + Typography, + useDebounce, +} from '@neo4j-ndl/react'; import { useCallback, useEffect, useRef, useState } from 'react'; -import { ExtendedNode, GraphType, GraphViewModalProps, Scheme, UserCredentials } from '../../types'; +import { + ExtendedNode, + ExtendedRelationship, + GraphType, + GraphViewModalProps, + Scheme, + UserCredentials, +} from '../../types'; import { InteractiveNvlWrapper } from '@neo4j-nvl/react'; import NVL from '@neo4j-nvl/base'; import type { Node, Relationship } from '@neo4j-nvl/base'; @@ -9,16 +26,26 @@ import { ArrowPathIconOutline, DragIcon, FitToScreenIcon, + MagnifyingGlassIconOutline, MagnifyingGlassMinusIconOutline, MagnifyingGlassPlusIconOutline, } from '@neo4j-ndl/react/icons'; import IconButtonWithToolTip from '../UI/IconButtonToolTip'; -import { filterData, processGraphData } from '../../utils/Utils'; +import { filterData, processGraphData, sortAlphabetically } from '../../utils/Utils'; import { useCredentials } from '../../context/UserCredentials'; import { LegendsChip } from './LegendsChip'; import graphQueryAPI from '../../services/GraphQuery'; -import { graphLabels, intitalGraphType, mouseEventCallbacks, nvlOptions, queryMap } from '../../utils/Constants'; +import { + graphLabels, + intitalGraphType, + mouseEventCallbacks, + nvlOptions, + queryMap, + RESULT_STEP_SIZE, +} from '../../utils/Constants'; import CheckboxSelection from './CheckboxSelection'; +import { ShowAll } from '../UI/ShowAll'; + const GraphViewModal: React.FunctionComponent = ({ open, inspectedName, @@ -40,6 +67,10 @@ const GraphViewModal: React.FunctionComponent = ({ const { userCredentials } = useCredentials(); const [scheme, setScheme] = useState({}); const [newScheme, setNewScheme] = useState({}); + const [searchQuery, setSearchQuery] = useState(''); + const debouncedQuery = useDebounce(searchQuery, 300); + + // the checkbox selection const handleCheckboxChange = (graph: GraphType) => { const currentIndex = graphType.indexOf(graph); const newGraphSelected = [...graphType]; @@ -50,18 +81,28 @@ const GraphViewModal: React.FunctionComponent = ({ newGraphSelected.splice(currentIndex, 1); initGraph(newGraphSelected, allNodes, allRelationships, scheme); } + setSearchQuery(''); setGraphType(newGraphSelected); }; + const nodeCount = (nodes: ExtendedNode[], label: string): number => { + return [...new Set(nodes?.filter((n) => n.labels?.includes(label)).map((i) => i.id))].length; + }; + + const relationshipCount = (relationships: ExtendedRelationship[], label: string): number => { + return [...new Set(relationships?.filter((r) => r.caption?.includes(label)).map((i) => i.id))].length; + }; + const graphQuery: string = graphType.includes('DocumentChunk') && graphType.includes('Entities') ? queryMap.DocChunkEntities : graphType.includes('DocumentChunk') - ? queryMap.DocChunks - : graphType.includes('Entities') - ? queryMap.Entities - : ''; + ? queryMap.DocChunks + : graphType.includes('Entities') + ? queryMap.Entities + : ''; + // fit graph to original position const handleZoomToFit = () => { nvlRef.current?.fit( allNodes.map((node) => node.id), @@ -75,7 +116,9 @@ const GraphViewModal: React.FunctionComponent = ({ handleZoomToFit(); }, 10); return () => { - nvlRef.current?.destroy(); + if (nvlRef.current) { + nvlRef.current?.destroy(); + } setGraphType(intitalGraphType); clearTimeout(timeoutId); setScheme({}); @@ -83,6 +126,7 @@ const GraphViewModal: React.FunctionComponent = ({ setRelationships([]); setAllNodes([]); setAllRelationships([]); + setSearchQuery(''); }; }, []); @@ -91,10 +135,10 @@ const GraphViewModal: React.FunctionComponent = ({ const nodeRelationshipData = viewPoint === graphLabels.showGraphView ? await graphQueryAPI( - userCredentials as UserCredentials, - graphQuery, - selectedRows?.map((f) => f.name) - ) + userCredentials as UserCredentials, + graphQuery, + selectedRows?.map((f) => f.name) + ) : await graphQueryAPI(userCredentials as UserCredentials, graphQuery, [inspectedName ?? '']); return nodeRelationshipData; } catch (error: any) { @@ -151,6 +195,64 @@ const GraphViewModal: React.FunctionComponent = ({ } }, [open]); + // The search and update nodes + const handleSearch = useCallback((value: string) => { + const query = value.toLowerCase(); + const updatedNodes = nodes.map((node) => { + if (query === '') { + return { + ...node, + activated: false, + selected: false, + size: graphLabels.nodeSize + }; + } + const { id, properties, caption } = node; + const propertiesMatch = properties?.id?.toLowerCase().includes(query); + const match = id.toLowerCase().includes(query) || propertiesMatch || caption?.toLowerCase().includes(query); + return { + ...node, + activated: match, + selected: match, + size: (match && viewPoint === graphLabels.showGraphView) ? 100 : (match && viewPoint !== graphLabels.showGraphView) ? 50 : graphLabels.nodeSize + }; + + }); + // deactivating any active relationships + const updatedRelationships = relationships.map((rel) => { + return { + ...rel, + activated: false, + selected: false, + }; + }); + setNodes(updatedNodes); + setRelationships(updatedRelationships); + }, [nodes]); + + useEffect(() => { + handleSearch(debouncedQuery) + }, [debouncedQuery]) + + const initGraph = ( + graphType: GraphType[], + finalNodes: ExtendedNode[], + finalRels: Relationship[], + schemeVal: Scheme + ) => { + if (allNodes.length > 0 && allRelationships.length > 0) { + const { filteredNodes, filteredRelations, filteredScheme } = filterData( + graphType, + finalNodes ?? [], + finalRels ?? [], + schemeVal + ); + setNodes(filteredNodes); + setRelationships(filteredRelations); + setNewScheme(filteredScheme); + } + }; + // Unmounting the component if (!open) { return <>; @@ -201,10 +303,11 @@ const GraphViewModal: React.FunctionComponent = ({ setRelationships([]); setAllNodes([]); setAllRelationships([]); + setSearchQuery(''); }; // sort the legends in with Chunk and Document always the first two values - const legendCheck = Object.keys(newScheme).sort((a, b) => { + const nodeCheck = Object.keys(newScheme).sort((a, b) => { if (a === graphLabels.document || a === graphLabels.chunk) { return -1; } else if (b === graphLabels.document || b === graphLabels.chunk) { @@ -213,23 +316,70 @@ const GraphViewModal: React.FunctionComponent = ({ return a.localeCompare(b); }); - const initGraph = ( - graphType: GraphType[], - finalNodes: ExtendedNode[], - finalRels: Relationship[], - schemeVal: Scheme - ) => { - if (allNodes.length > 0 && allRelationships.length > 0) { - const { filteredNodes, filteredRelations, filteredScheme } = filterData( - graphType, - finalNodes ?? [], - finalRels ?? [], - schemeVal - ); - setNodes(filteredNodes); - setRelationships(filteredRelations); - setNewScheme(filteredScheme); + // get sorted relationships + const relationshipsSorted = relationships.sort(sortAlphabetically); + + // To get the relationship count + const groupedAndSortedRelationships: ExtendedRelationship[] = Object.values( + relationshipsSorted.reduce((acc: { [key: string]: ExtendedRelationship }, relType: Relationship) => { + const key = relType.caption || ''; + if (!acc[key]) { + acc[key] = { ...relType, count: 0 }; + } + + acc[key]!.count += relationshipCount(relationships as ExtendedRelationship[], key); + return acc; + }, {}) + ); + + // On Node Click, highlighting the nodes and deactivating any active relationships + const handleNodeClick = (nodeLabel: string) => { + const updatedNodes = nodes.map((node) => { + const isActive = node.labels.includes(nodeLabel); + return { + ...node, + activated: isActive, + selected: isActive, + size: (isActive && viewPoint === graphLabels.showGraphView) ? 100 : (isActive && viewPoint !== graphLabels.showGraphView) ? 50 : graphLabels.nodeSize + }; + }); + // deactivating any active relationships + const updatedRelationships = relationships.map((rel) => { + return { + ...rel, + activated: false, + selected: false, + }; + }); + if (searchQuery !== '') { + setSearchQuery(''); } + setNodes(updatedNodes); + setRelationships(updatedRelationships); + }; + // On Relationship Legend Click, highlight the relationships and deactivating any active nodes + const handleRelationshipClick = (nodeLabel: string) => { + const updatedRelations = relationships.map((rel) => { + return { + ...rel, + activated: rel?.caption?.includes(nodeLabel), + selected: rel?.caption?.includes(nodeLabel), + }; + }); + // // deactivating any active nodes + const updatedNodes = nodes.map((node) => { + return { + ...node, + activated: false, + selected: false, + size: graphLabels.nodeSize + }; + }); + if (searchQuery !== '') { + setSearchQuery(''); + } + setRelationships(updatedRelations); + setNodes(updatedNodes); }; return ( @@ -334,17 +484,79 @@ const GraphViewModal: React.FunctionComponent = ({ handleClasses={{ left: 'ml-1' }} >
- - {graphLabels.resultOverview} - - {graphLabels.totalNodes} ({nodes.length}) - - -
- {legendCheck.map((key, index) => ( - - ))} -
+ {nodeCheck.length > 0 && ( + <> + + {graphLabels.resultOverview} +
+ { + setSearchQuery(e.target.value); + }} + placeholder='Search On Node Properties' + fluid={true} + leftIcon={ + + + + } + /> +
+ + {graphLabels.totalNodes} ({nodes.length}) + +
+
+ + {nodeCheck.map((nodeLabel, index) => ( + handleNodeClick(nodeLabel)} + /> + ))} + +
+ + )} + {relationshipsSorted.length > 0 && ( + <> + + + {graphLabels.totalRelationships} ({relationships.length}) + + +
+ + {groupedAndSortedRelationships.map((relType, index) => ( + handleRelationshipClick(relType.caption || '')} + /> + ))} + +
+ + )}
diff --git a/frontend/src/components/Graph/LegendsChip.tsx b/frontend/src/components/Graph/LegendsChip.tsx index 7d2de8b74..2fdc16df2 100644 --- a/frontend/src/components/Graph/LegendsChip.tsx +++ b/frontend/src/components/Graph/LegendsChip.tsx @@ -1,12 +1,14 @@ -import { useMemo } from 'react'; import { LegendChipProps } from '../../types'; import Legend from '../UI/Legend'; -export const LegendsChip: React.FunctionComponent = ({ scheme, title, nodes }) => { - const chunkcount = useMemo( - () => [...new Set(nodes?.filter((n) => n?.labels?.includes(title)).map((i) => i.id))].length, - [] +export const LegendsChip: React.FunctionComponent = ({ + scheme, + label, + type, + count, + onClick, +}) => { + return ( + ); - - return ; }; diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx index bf8345550..36fcff3d1 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx @@ -80,12 +80,12 @@ export default function DeduplicationTab() { const onRemove = (nodeid: string, similarNodeId: string) => { setDuplicateNodes((prev) => { return prev.map((d) => - (d.e.elementId === nodeid + d.e.elementId === nodeid ? { ...d, similar: d.similar.filter((n) => n.elementId != similarNodeId), } - : d) + : d ); }); }; @@ -160,7 +160,7 @@ export default function DeduplicationTab() { return ( {info.getValue().map((l, index) => ( - + ))} ); diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx index 9cdf239dc..f836c9e87 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx @@ -111,7 +111,7 @@ export default function DeletePopUpForOrphanNodes({ return ( {info.getValue().map((l, index) => ( - + ))} ); diff --git a/frontend/src/components/UI/Legend.tsx b/frontend/src/components/UI/Legend.tsx index d798ff4f4..a3c806669 100644 --- a/frontend/src/components/UI/Legend.tsx +++ b/frontend/src/components/UI/Legend.tsx @@ -3,16 +3,20 @@ import { GraphLabel } from '@neo4j-ndl/react'; export default function Legend({ bgColor, title, - chunkCount, + count, + type, + onClick, }: { bgColor: string; title: string; - chunkCount?: number; + count?: number; + type: 'node' | 'relationship' | 'propertyKey'; + tabIndex?: number; + onClick?: (e: React.MouseEvent) => void; }) { return ( - - {title} - {chunkCount && `(${chunkCount})`} + + {title} {count !== undefined && `(${count})`} ); } diff --git a/frontend/src/components/UI/ShowAll.tsx b/frontend/src/components/UI/ShowAll.tsx new file mode 100644 index 000000000..726146723 --- /dev/null +++ b/frontend/src/components/UI/ShowAll.tsx @@ -0,0 +1,38 @@ +import { Button } from '@neo4j-ndl/react'; +import type { ReactNode } from 'react'; +import { useState } from 'react'; + +// import { ButtonGroup } from '../button-group/button-group'; + +type ShowAllProps = { + initiallyShown: number; + /* pass thunk to enable rendering only shown components */ + children: ((() => ReactNode) | ReactNode)[]; + ariaLabel?: string; +}; +const isThunkComponent = (t: (() => ReactNode) | ReactNode): t is () => ReactNode => typeof t === 'function'; + +export function ShowAll({ initiallyShown, children }: ShowAllProps) { + const [expanded, setExpanded] = useState(false); + const toggleExpanded = () => setExpanded((e) => !e); + const itemCount = children.length; + const controlsNeeded = itemCount > initiallyShown; + const shown = expanded ? itemCount : initiallyShown; + const leftToShow = itemCount - shown; + + if (itemCount === 0) { + return null; + } + + const currentChildren = children.slice(0, shown).map((c) => (isThunkComponent(c) ? c() : c)); + return ( + <> +
{currentChildren}
+ {controlsNeeded && ( + + )} + + ); +} diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 8e05f632b..5bf076d10 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -259,7 +259,7 @@ export interface GraphViewModalProps { setGraphViewOpen: Dispatch>; viewPoint: string; nodeValues?: ExtendedNode[]; - relationshipValues?: Relationship[]; + relationshipValues?: ExtendedRelationship[]; selectedRows?: CustomFile[] | undefined; } @@ -344,13 +344,13 @@ export type alertStateType = { export type Scheme = Record; export type LabelCount = Record; -interface NodeType extends Partial { - labels?: string[]; -} + export interface LegendChipProps { scheme: Scheme; - title: string; - nodes: NodeType[]; + label: string; + type: 'node' | 'relationship' | 'propertyKey'; + count: number; + onClick: (e: React.MouseEvent) => void; } export interface FileContextProviderProps { children: ReactNode; @@ -578,29 +578,6 @@ export type GraphStatsLabels = Record< } >; -type NodeStyling = { - backgroundColor: string; - borderColor: string; - textColor: string; - caption: string; - diameter: string; -}; - -type RelationStyling = { - fontSize: string; - lineColor: string; - textColorExternal: string; - textColorInternal: string; - caption: string; - padding: string; - width: string; -}; - -export type GraphStyling = { - node: Record>; - relationship: Record>; -}; - export interface ExtendedNode extends Node { labels: string[]; properties: { @@ -610,7 +587,7 @@ export interface ExtendedNode extends Node { } export interface ExtendedRelationship extends Relationship { - labels: string[]; + count: number; } export interface connectionState { openPopUp: boolean; @@ -655,7 +632,7 @@ export interface S3File { } export interface GraphViewButtonProps { nodeValues?: ExtendedNode[]; - relationshipValues?: Relationship[]; + relationshipValues?: ExtendedRelationship[]; } export interface DrawerChatbotProps { isExpanded: boolean; diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index b4781b929..33e1d1a04 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -231,4 +231,8 @@ export const graphLabels = { totalNodes: 'Total Nodes', noEntities: 'No Entities Found', selectCheckbox: 'Select atleast one checkbox for graph view', + totalRelationships: 'Total Relationships', + nodeSize: 30 }; + +export const RESULT_STEP_SIZE = 25; diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index 9745993f6..0b8b05841 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -1,6 +1,6 @@ import { calcWordColor } from '@neo4j-devtools/word-color'; import type { Relationship } from '@neo4j-nvl/base'; -import { Entity, ExtendedNode, GraphType, Messages, Scheme } from '../types'; +import { Entity, ExtendedNode, ExtendedRelationship, GraphType, Messages, Scheme } from '../types'; // Get the Url export const url = () => { @@ -130,7 +130,7 @@ export function extractPdfFileName(url: string): string { return decodedFileName; } -export const processGraphData = (neoNodes: ExtendedNode[], neoRels: Relationship[]) => { +export const processGraphData = (neoNodes: ExtendedNode[], neoRels: ExtendedRelationship[]) => { const schemeVal: Scheme = {}; let iterator = 0; const labels: string[] = neoNodes.map((f: any) => f.labels); @@ -239,3 +239,9 @@ export const parseEntity = (entity: Entity) => { export const titleCheck = (title: string) => { return title === 'Chunk' || title === 'Document'; }; + +export const sortAlphabetically = (a: Relationship, b: Relationship) => { + const captionOne = a.caption?.toLowerCase() || ''; + const captionTwo = b.caption?.toLowerCase() || ''; + return captionOne.localeCompare(captionTwo); +}; diff --git a/frontend/yarn.lock b/frontend/yarn.lock index c91c34832..3915845ef 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -6614,4 +6614,4 @@ yocto-queue@^0.1.0: zwitch@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-2.0.4.tgz#c827d4b0acb76fc3e685a4c6ec2902d51070e9d7" - integrity sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A== + integrity sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A== \ No newline at end of file From 45751980adc8ffb6c03df95c97f8b9550f128b9a Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Wed, 21 Aug 2024 17:28:11 +0530 Subject: [PATCH 014/292] changed chat mode names (#702) --- backend/src/QA_integration_new.py | 4 ++-- frontend/src/utils/Constants.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/src/QA_integration_new.py b/backend/src/QA_integration_new.py index 5a2baa599..9ab42a497 100644 --- a/backend/src/QA_integration_new.py +++ b/backend/src/QA_integration_new.py @@ -41,7 +41,7 @@ def get_neo4j_retriever(graph, retrieval_query,document_names,mode,index_name="vector",keyword_index="keyword", search_k=CHAT_SEARCH_KWARG_K, score_threshold=CHAT_SEARCH_KWARG_SCORE_THRESHOLD): try: - if mode == "hybrid" or mode == "hybrid+graph": + if mode == "fulltext" or mode == "fulltext+graph": neo_db = Neo4jVector.from_existing_graph( embedding=EMBEDDING_FUNCTION, index_name=index_name, @@ -374,7 +374,7 @@ def QA_RAG(graph, model, question, document_names,session_id, mode): "user": "chatbot" } return result - elif mode == "vector" or mode == "hybrid": + elif mode == "vector" or mode == "fulltext": retrieval_query = VECTOR_SEARCH_QUERY else: retrieval_query = VECTOR_GRAPH_SEARCH_QUERY.format(no_of_entites=VECTOR_GRAPH_SEARCH_ENTITY_LIMIT) diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index 33e1d1a04..ee2296a3a 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -59,7 +59,7 @@ export const defaultLLM = llms?.includes('openai-gpt-4o-mini') export const chatModes = process.env?.VITE_CHAT_MODES?.trim() != '' ? process.env.VITE_CHAT_MODES?.split(',') - : ['vector', 'graph', 'graph+vector', 'hybrid', 'hybrid+graph']; + : ['vector', 'graph', 'graph+vector', 'fulltext', 'fulltext+graph']; export const chunkSize = process.env.VITE_CHUNK_SIZE ? parseInt(process.env.VITE_CHUNK_SIZE) : 1 * 1024 * 1024; export const timeperpage = process.env.VITE_TIME_PER_PAGE ? parseInt(process.env.VITE_TIME_PER_PAGE) : 50; export const timePerByte = 0.2; From a6ee3451aaf62700d393a16b8809d59303a8d345 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Wed, 21 Aug 2024 12:58:28 +0000 Subject: [PATCH 015/292] env changes --- README.md | 2 +- example.env | 1 - frontend/Dockerfile | 3 +-- frontend/example.env | 1 - 4 files changed, 2 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 800721ec3..e0b59346d 100644 --- a/README.md +++ b/README.md @@ -149,7 +149,7 @@ Allow unauthenticated request : Yes | VITE_LLM_MODELS | Mandatory | diffbot,openai-gpt-3.5,openai-gpt-4o | Models available for selection on the frontend, used for entities extraction and Q&A | VITE_CHAT_MODES | Mandatory | vector,graph+vector,graph,hybrid | Chat modes available for Q&A | VITE_ENV | Mandatory | DEV or PROD | Environment variable for the app | -| VITE_TIME_PER_CHUNK | Optional | 4 | Time per chunk for processing | +| VITE_TIME_PER_PAGE | Optional | 50 | Time per page for processing | | VITE_CHUNK_SIZE | Optional | 5242880 | Size of each chunk of file for upload | | VITE_GOOGLE_CLIENT_ID | Optional | | Client ID for Google authentication | | GCS_FILE_CACHE | Optional | False | If set to True, will save the files to process into GCS. If set to False, will save the files locally | diff --git a/example.env b/example.env index b50e3e985..ed33101fb 100644 --- a/example.env +++ b/example.env @@ -30,7 +30,6 @@ VITE_BLOOM_URL="https://workspace-preview.neo4j.io/workspace/explore?connectURL= VITE_REACT_APP_SOURCES="local,youtube,wiki,s3,web" VITE_LLM_MODELS="diffbot,openai-gpt-3.5,openai-gpt-4o" # ",ollama_llama3" VITE_ENV="DEV" -VITE_TIME_PER_CHUNK=4 VITE_TIME_PER_PAGE=50 VITE_CHUNK_SIZE=5242880 VITE_GOOGLE_CLIENT_ID="" diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 7a31d5bcf..c3a7c1c82 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -6,7 +6,6 @@ ARG VITE_REACT_APP_SOURCES="" ARG VITE_LLM_MODELS="" ARG VITE_GOOGLE_CLIENT_ID="" ARG VITE_BLOOM_URL="https://workspace-preview.neo4j.io/workspace/explore?connectURL={CONNECT_URL}&search=Show+me+a+graph&featureGenAISuggestions=true&featureGenAISuggestionsInternal=true" -ARG VITE_TIME_PER_CHUNK=4 ARG VITE_TIME_PER_PAGE=50 ARG VITE_LARGE_FILE_SIZE=5242880 ARG VITE_CHUNK_SIZE=5242880 @@ -23,8 +22,8 @@ RUN VITE_BACKEND_API_URL=$VITE_BACKEND_API_URL \ VITE_LLM_MODELS=$VITE_LLM_MODELS \ VITE_GOOGLE_CLIENT_ID=$VITE_GOOGLE_CLIENT_ID \ VITE_BLOOM_URL=$VITE_BLOOM_URL \ - VITE_TIME_PER_CHUNK=$VITE_TIME_PER_CHUNK \ VITE_CHUNK_SIZE=$VITE_CHUNK_SIZE \ + VITE_TIME_PER_PAGE=$VITE_TIME_PER_PAGE \ VITE_ENV=$VITE_ENV \ VITE_LARGE_FILE_SIZE=${VITE_LARGE_FILE_SIZE} \ VITE_CHAT_MODES=$VITE_CHAT_MODES \ diff --git a/frontend/example.env b/frontend/example.env index 05b8cdf60..63bd3e7c3 100644 --- a/frontend/example.env +++ b/frontend/example.env @@ -3,7 +3,6 @@ VITE_BLOOM_URL="https://workspace-preview.neo4j.io/workspace/explore?connectURL= VITE_REACT_APP_SOURCES="local,youtube,wiki,s3,web" VITE_LLM_MODELS="diffbot,openai-gpt-3.5,openai-gpt-4o" VITE_ENV="DEV" -VITE_TIME_PER_CHUNK=4 VITE_TIME_PER_PAGE=50 VITE_CHUNK_SIZE=5242880 VITE_LARGE_FILE_SIZE=5242880 From dc351a074d3bc56d9662a844796512febd627a3b Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Thu, 22 Aug 2024 06:32:43 +0000 Subject: [PATCH 016/292] used axios instance for network calls --- frontend/src/API/Index.ts | 7 +++++++ frontend/src/services/CancelAPI.ts | 5 ++--- frontend/src/services/ChunkEntitiesInfo.ts | 5 ++--- frontend/src/services/CommonAPI.ts | 5 +++-- frontend/src/services/ConnectAPI.ts | 5 ++--- frontend/src/services/DeleteFiles.ts | 5 ++--- frontend/src/services/DeleteOrphanNodes.ts | 5 ++--- frontend/src/services/GetDuplicateNodes.ts | 5 ++--- frontend/src/services/GetFiles.ts | 7 +++---- frontend/src/services/GetNodeLabelsRelTypes.ts | 5 ++--- frontend/src/services/GetOrphanNodes.ts | 5 ++--- frontend/src/services/GraphQuery.ts | 5 ++--- frontend/src/services/HealthStatus.ts | 7 +++---- frontend/src/services/MergeDuplicateEntities.ts | 5 ++--- frontend/src/services/PollingAPI.ts | 7 +++---- frontend/src/services/PostProcessing.ts | 5 ++--- frontend/src/services/QnaAPI.ts | 7 +++---- frontend/src/services/SchemaFromTextAPI.ts | 5 ++--- frontend/src/services/URLScan.ts | 5 ++--- frontend/src/services/vectorIndexCreation.ts | 5 ++--- 20 files changed, 50 insertions(+), 60 deletions(-) create mode 100644 frontend/src/API/Index.ts diff --git a/frontend/src/API/Index.ts b/frontend/src/API/Index.ts new file mode 100644 index 000000000..d086970e4 --- /dev/null +++ b/frontend/src/API/Index.ts @@ -0,0 +1,7 @@ +import axios from 'axios' +import { url } from '../utils/Utils' + +const api=axios.create({ + baseURL:url() +}) +export default api \ No newline at end of file diff --git a/frontend/src/services/CancelAPI.ts b/frontend/src/services/CancelAPI.ts index a162bed83..de3ea9ba0 100644 --- a/frontend/src/services/CancelAPI.ts +++ b/frontend/src/services/CancelAPI.ts @@ -1,6 +1,5 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; import { UserCredentials, commonserverresponse } from '../types'; +import api from '../API/Index'; const cancelAPI = async (filenames: string[], source_types: string[]) => { try { @@ -14,7 +13,7 @@ const cancelAPI = async (filenames: string[], source_types: string[]) => { } formData.append('filenames', JSON.stringify(filenames)); formData.append('source_types', JSON.stringify(source_types)); - const response = await axios.post(`${url()}/cancelled_job`, formData); + const response = await api.post(`/cancelled_job`, formData); return response; } catch (error) { console.log('Error Posting the Question:', error); diff --git a/frontend/src/services/ChunkEntitiesInfo.ts b/frontend/src/services/ChunkEntitiesInfo.ts index 3b4323197..aa133c815 100644 --- a/frontend/src/services/ChunkEntitiesInfo.ts +++ b/frontend/src/services/ChunkEntitiesInfo.ts @@ -1,6 +1,5 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; import { ChatInfo_APIResponse, UserCredentials } from '../types'; +import api from '../API/Index'; const chunkEntitiesAPI = async (userCredentials: UserCredentials, chunk_ids: string) => { try { @@ -10,7 +9,7 @@ const chunkEntitiesAPI = async (userCredentials: UserCredentials, chunk_ids: str formData.append('password', userCredentials?.password ?? ''); formData.append('chunk_ids', chunk_ids); - const response: ChatInfo_APIResponse = await axios.post(`${url()}/chunk_entities`, formData, { + const response: ChatInfo_APIResponse = await api.post(`/chunk_entities`, formData, { headers: { 'Content-Type': 'multipart/form-data', }, diff --git a/frontend/src/services/CommonAPI.ts b/frontend/src/services/CommonAPI.ts index 78d324248..bbae83032 100644 --- a/frontend/src/services/CommonAPI.ts +++ b/frontend/src/services/CommonAPI.ts @@ -1,5 +1,6 @@ -import axios, { AxiosResponse, Method } from 'axios'; +import { AxiosResponse, Method } from 'axios'; import { UserCredentials, FormDataParams } from '../types'; +import api from '../API/Index'; // API Call const apiCall = async ( @@ -16,7 +17,7 @@ const apiCall = async ( for (const key in additionalParams) { formData.append(key, additionalParams[key]); } - const response: AxiosResponse = await axios({ + const response: AxiosResponse = await api({ method: method, url: url, data: formData, diff --git a/frontend/src/services/ConnectAPI.ts b/frontend/src/services/ConnectAPI.ts index 73d997b1e..026c41c44 100644 --- a/frontend/src/services/ConnectAPI.ts +++ b/frontend/src/services/ConnectAPI.ts @@ -1,5 +1,4 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; +import api from '../API/Index'; const connectAPI = async (connectionURI: string, username: string, password: string, database: string) => { try { @@ -8,7 +7,7 @@ const connectAPI = async (connectionURI: string, username: string, password: str formData.append('database', database ?? ''); formData.append('userName', username ?? ''); formData.append('password', password ?? ''); - const response = await axios.post(`${url()}/connect`, formData, { + const response = await api.post(`/connect`, formData, { headers: { 'Content-Type': 'multipart/form-data', }, diff --git a/frontend/src/services/DeleteFiles.ts b/frontend/src/services/DeleteFiles.ts index 36ae28cbd..a86ef187e 100644 --- a/frontend/src/services/DeleteFiles.ts +++ b/frontend/src/services/DeleteFiles.ts @@ -1,6 +1,5 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; import { CustomFile, UserCredentials } from '../types'; +import api from '../API/Index'; const deleteAPI = async (userCredentials: UserCredentials, selectedFiles: CustomFile[], deleteEntities: boolean) => { try { @@ -14,7 +13,7 @@ const deleteAPI = async (userCredentials: UserCredentials, selectedFiles: Custom formData.append('deleteEntities', JSON.stringify(deleteEntities)); formData.append('filenames', JSON.stringify(filenames)); formData.append('source_types', JSON.stringify(source_types)); - const response = await axios.post(`${url()}/delete_document_and_entities`, formData); + const response = await api.post(`/delete_document_and_entities`, formData); return response; } catch (error) { console.log('Error Posting the Question:', error); diff --git a/frontend/src/services/DeleteOrphanNodes.ts b/frontend/src/services/DeleteOrphanNodes.ts index 135dfcdeb..2cebc572c 100644 --- a/frontend/src/services/DeleteOrphanNodes.ts +++ b/frontend/src/services/DeleteOrphanNodes.ts @@ -1,6 +1,5 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; import { UserCredentials } from '../types'; +import api from '../API/Index'; const deleteOrphanAPI = async (userCredentials: UserCredentials, selectedNodes: string[]) => { try { @@ -10,7 +9,7 @@ const deleteOrphanAPI = async (userCredentials: UserCredentials, selectedNodes: formData.append('userName', userCredentials?.userName ?? ''); formData.append('password', userCredentials?.password ?? ''); formData.append('unconnected_entities_list', JSON.stringify(selectedNodes)); - const response = await axios.post(`${url()}/delete_unconnected_nodes`, formData); + const response = await api.post(`/delete_unconnected_nodes`, formData); return response; } catch (error) { console.log('Error Posting the Question:', error); diff --git a/frontend/src/services/GetDuplicateNodes.ts b/frontend/src/services/GetDuplicateNodes.ts index 3cb27a970..b7ea0c426 100644 --- a/frontend/src/services/GetDuplicateNodes.ts +++ b/frontend/src/services/GetDuplicateNodes.ts @@ -1,6 +1,5 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; import { duplicateNodesData, UserCredentials } from '../types'; +import api from '../API/Index'; export const getDuplicateNodes = async (userCredentials: UserCredentials) => { const formData = new FormData(); @@ -9,7 +8,7 @@ export const getDuplicateNodes = async (userCredentials: UserCredentials) => { formData.append('userName', userCredentials?.userName ?? ''); formData.append('password', userCredentials?.password ?? ''); try { - const response = await axios.post(`${url()}/get_duplicate_nodes`, formData); + const response = await api.post(`/get_duplicate_nodes`, formData); return response; } catch (error) { console.log(error); diff --git a/frontend/src/services/GetFiles.ts b/frontend/src/services/GetFiles.ts index fd8d60fba..0744ff047 100644 --- a/frontend/src/services/GetFiles.ts +++ b/frontend/src/services/GetFiles.ts @@ -1,12 +1,11 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; import { SourceListServerData, UserCredentials } from '../types'; +import api from '../API/Index'; export const getSourceNodes = async (userCredentials: UserCredentials) => { try { const encodedstr = btoa(userCredentials.password); - const response = await axios.get( - `${url()}/sources_list?uri=${userCredentials.uri}&database=${userCredentials.database}&userName=${ + const response = await api.get( + `/sources_list?uri=${userCredentials.uri}&database=${userCredentials.database}&userName=${ userCredentials.userName }&password=${encodedstr}` ); diff --git a/frontend/src/services/GetNodeLabelsRelTypes.ts b/frontend/src/services/GetNodeLabelsRelTypes.ts index acc05f267..8c7345c2a 100644 --- a/frontend/src/services/GetNodeLabelsRelTypes.ts +++ b/frontend/src/services/GetNodeLabelsRelTypes.ts @@ -1,6 +1,5 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; import { ServerData, UserCredentials } from '../types'; +import api from '../API/Index'; export const getNodeLabelsAndRelTypes = async (userCredentials: UserCredentials) => { const formData = new FormData(); @@ -9,7 +8,7 @@ export const getNodeLabelsAndRelTypes = async (userCredentials: UserCredentials) formData.append('userName', userCredentials?.userName ?? ''); formData.append('password', userCredentials?.password ?? ''); try { - const response = await axios.post(`${url()}/schema`, formData); + const response = await api.post(`/schema`, formData); return response; } catch (error) { console.log(error); diff --git a/frontend/src/services/GetOrphanNodes.ts b/frontend/src/services/GetOrphanNodes.ts index 70cfe8cda..3578214d1 100644 --- a/frontend/src/services/GetOrphanNodes.ts +++ b/frontend/src/services/GetOrphanNodes.ts @@ -1,6 +1,5 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; import { OrphanNodeResponse, UserCredentials } from '../types'; +import api from '../API/Index'; export const getOrphanNodes = async (userCredentials: UserCredentials) => { const formData = new FormData(); @@ -9,7 +8,7 @@ export const getOrphanNodes = async (userCredentials: UserCredentials) => { formData.append('userName', userCredentials?.userName ?? ''); formData.append('password', userCredentials?.password ?? ''); try { - const response = await axios.post(`${url()}/get_unconnected_nodes_list`, formData); + const response = await api.post(`/get_unconnected_nodes_list`, formData); return response; } catch (error) { console.log(error); diff --git a/frontend/src/services/GraphQuery.ts b/frontend/src/services/GraphQuery.ts index 55d22a5ee..f792f4aec 100644 --- a/frontend/src/services/GraphQuery.ts +++ b/frontend/src/services/GraphQuery.ts @@ -1,6 +1,5 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; import { UserCredentials } from '../types'; +import api from '../API/Index'; const graphQueryAPI = async ( userCredentials: UserCredentials, @@ -16,7 +15,7 @@ const graphQueryAPI = async ( formData.append('query_type', query_type ?? 'entities'); formData.append('document_names', JSON.stringify(document_names)); - const response = await axios.post(`${url()}/graph_query`, formData, { + const response = await api.post(`/graph_query`, formData, { headers: { 'Content-Type': 'multipart/form-data', }, diff --git a/frontend/src/services/HealthStatus.ts b/frontend/src/services/HealthStatus.ts index 69a77f0fe..a59badbe0 100644 --- a/frontend/src/services/HealthStatus.ts +++ b/frontend/src/services/HealthStatus.ts @@ -1,9 +1,8 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; +import api from '../API/Index'; const healthStatus = async () => { try { - const healthUrl = `${url()}/health`; - const response = await axios.get(healthUrl); + const healthUrl = `/health`; + const response = await api.get(healthUrl); return response; } catch (error) { console.log('API status error', error); diff --git a/frontend/src/services/MergeDuplicateEntities.ts b/frontend/src/services/MergeDuplicateEntities.ts index ee4e0fffb..1fdb9b387 100644 --- a/frontend/src/services/MergeDuplicateEntities.ts +++ b/frontend/src/services/MergeDuplicateEntities.ts @@ -1,6 +1,5 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; import { commonserverresponse, selectedDuplicateNodes, UserCredentials } from '../types'; +import api from '../API/Index'; const mergeDuplicateNodes = async (userCredentials: UserCredentials, selectedNodes: selectedDuplicateNodes[]) => { try { @@ -10,7 +9,7 @@ const mergeDuplicateNodes = async (userCredentials: UserCredentials, selectedNod formData.append('userName', userCredentials?.userName ?? ''); formData.append('password', userCredentials?.password ?? ''); formData.append('duplicate_nodes_list', JSON.stringify(selectedNodes)); - const response = await axios.post(`${url()}/merge_duplicate_nodes`, formData); + const response = await api.post(`/merge_duplicate_nodes`, formData); return response; } catch (error) { console.log('Error Merging the duplicate nodes:', error); diff --git a/frontend/src/services/PollingAPI.ts b/frontend/src/services/PollingAPI.ts index baa2e6080..f14ed0580 100644 --- a/frontend/src/services/PollingAPI.ts +++ b/frontend/src/services/PollingAPI.ts @@ -1,6 +1,5 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; import { PollingAPI_Response, statusupdate } from '../types'; +import api from '../API/Index'; export default async function subscribe( fileName: string, @@ -19,8 +18,8 @@ export default async function subscribe( while (pollingAttempts < MAX_POLLING_ATTEMPTS) { let currentdelay = delay; - let response: PollingAPI_Response = await axios.get( - `${url()}/document_status/${fileName}?url=${uri}&userName=${username}&password=${encodedstr}&database=${database}` + let response: PollingAPI_Response = await api.get( + `/document_status/${fileName}?url=${uri}&userName=${username}&password=${encodedstr}&database=${database}` ); if (response.data?.file_name?.status === 'Processing') { diff --git a/frontend/src/services/PostProcessing.ts b/frontend/src/services/PostProcessing.ts index 9f45cc6bd..98c94c238 100644 --- a/frontend/src/services/PostProcessing.ts +++ b/frontend/src/services/PostProcessing.ts @@ -1,6 +1,5 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; import { UserCredentials } from '../types'; +import api from '../API/Index'; const postProcessing = async (userCredentials: UserCredentials, taskParam: string[]) => { try { @@ -10,7 +9,7 @@ const postProcessing = async (userCredentials: UserCredentials, taskParam: strin formData.append('userName', userCredentials?.userName ?? ''); formData.append('password', userCredentials?.password ?? ''); formData.append('tasks', JSON.stringify(taskParam)); - const response = await axios.post(`${url()}/post_processing`, formData, { + const response = await api.post(`/post_processing`, formData, { headers: { 'Content-Type': 'multipart/form-data', }, diff --git a/frontend/src/services/QnaAPI.ts b/frontend/src/services/QnaAPI.ts index 931618839..78fa240ba 100644 --- a/frontend/src/services/QnaAPI.ts +++ b/frontend/src/services/QnaAPI.ts @@ -1,6 +1,5 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; import { UserCredentials } from '../types'; +import api from '../API/Index'; export const chatBotAPI = async ( userCredentials: UserCredentials, @@ -22,7 +21,7 @@ export const chatBotAPI = async ( formData.append('mode', mode); formData.append('document_names', JSON.stringify(document_names)); const startTime = Date.now(); - const response = await axios.post(`${url()}/chat_bot`, formData, { + const response = await api.post(`/chat_bot`, formData, { headers: { 'Content-Type': 'multipart/form-data', }, @@ -44,7 +43,7 @@ export const clearChatAPI = async (userCredentials: UserCredentials, session_id: formData.append('userName', userCredentials?.userName ?? ''); formData.append('password', userCredentials?.password ?? ''); formData.append('session_id', session_id); - const response = await axios.post(`${url()}/clear_chat_bot`, formData, { + const response = await api.post(`/clear_chat_bot`, formData, { headers: { 'Content-Type': 'multipart/form-data', }, diff --git a/frontend/src/services/SchemaFromTextAPI.ts b/frontend/src/services/SchemaFromTextAPI.ts index 785fb0d68..3d1984ccf 100644 --- a/frontend/src/services/SchemaFromTextAPI.ts +++ b/frontend/src/services/SchemaFromTextAPI.ts @@ -1,6 +1,5 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; import { ScehmaFromText } from '../types'; +import api from '../API/Index'; export const getNodeLabelsAndRelTypesFromText = async (model: string, inputText: string, isSchemaText: boolean) => { const formData = new FormData(); @@ -9,7 +8,7 @@ export const getNodeLabelsAndRelTypesFromText = async (model: string, inputText: formData.append('is_schema_description_checked', JSON.stringify(isSchemaText)); try { - const response = await axios.post(`${url()}/populate_graph_schema`, formData); + const response = await api.post(`/populate_graph_schema`, formData); return response; } catch (error) { console.log(error); diff --git a/frontend/src/services/URLScan.ts b/frontend/src/services/URLScan.ts index 58ad37dfb..444022934 100644 --- a/frontend/src/services/URLScan.ts +++ b/frontend/src/services/URLScan.ts @@ -1,6 +1,5 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; import { ScanProps, ServerResponse } from '../types'; +import api from '../API/Index'; const urlScanAPI = async (props: ScanProps) => { try { @@ -46,7 +45,7 @@ const urlScanAPI = async (props: ScanProps) => { formData.append('access_token', props.access_token); } - const response: ServerResponse = await axios.post(`${url()}/url/scan`, formData, { + const response: ServerResponse = await api.post(`/url/scan`, formData, { headers: { 'Content-Type': 'multipart/form-data', }, diff --git a/frontend/src/services/vectorIndexCreation.ts b/frontend/src/services/vectorIndexCreation.ts index accf85659..e89767551 100644 --- a/frontend/src/services/vectorIndexCreation.ts +++ b/frontend/src/services/vectorIndexCreation.ts @@ -1,6 +1,5 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; import { commonserverresponse, UserCredentials } from '../types'; +import api from '../API/Index'; export const createVectorIndex = async (userCredentials: UserCredentials, isVectorIndexExists: boolean) => { const formData = new FormData(); @@ -10,7 +9,7 @@ export const createVectorIndex = async (userCredentials: UserCredentials, isVect formData.append('password', userCredentials?.password ?? ''); formData.append('isVectorIndexExist', JSON.stringify(isVectorIndexExists)); try { - const response = await axios.post(`${url()}/drop_create_vector_index`, formData); + const response = await api.post(`/drop_create_vector_index`, formData); return response; } catch (error) { console.log(error); From a241c6bcbb64441c886231d72e738cee10f32ec2 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Thu, 22 Aug 2024 08:25:56 +0000 Subject: [PATCH 017/292] disabled the toolip when dropdown is open state --- frontend/src/components/Dropdown.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/Dropdown.tsx b/frontend/src/components/Dropdown.tsx index f046bb8ff..ed7c5fe6c 100644 --- a/frontend/src/components/Dropdown.tsx +++ b/frontend/src/components/Dropdown.tsx @@ -1,6 +1,6 @@ import { Dropdown, Tip } from '@neo4j-ndl/react'; import { OptionType, ReusableDropdownProps } from '../types'; -import { useMemo } from 'react'; +import { useMemo, useReducer } from 'react'; import { capitalize } from '../utils/Utils'; const DropdownComponent: React.FC = ({ @@ -13,6 +13,7 @@ const DropdownComponent: React.FC = ({ isDisabled, value, }) => { + const [disableTooltip, toggleDisableState] = useReducer((state)=>!state,false) const handleChange = (selectedOption: OptionType | null | void) => { onSelect(selectedOption); }; @@ -20,7 +21,7 @@ const DropdownComponent: React.FC = ({ return ( <>
- + = ({ menuPlacement: 'auto', isDisabled: isDisabled, value: value, + onMenuOpen:()=>{ + toggleDisableState() + }, + onMenuClose:()=>{ + toggleDisableState() + } }} size='medium' fluid From 426906bb5e2c7c2e71721195314c6c4211f55447 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Thu, 22 Aug 2024 08:32:39 +0000 Subject: [PATCH 018/292] format fixes + chat mode naming changes --- backend/src/QA_integration_new.py | 2 +- frontend/src/API/Index.ts | 12 +-- .../src/components/ChatBot/ChatModeToggle.tsx | 7 +- frontend/src/components/Dropdown.tsx | 12 +-- .../src/components/Graph/GraphViewModal.tsx | 94 +++++++++++-------- frontend/src/components/Graph/LegendsChip.tsx | 12 +-- frontend/src/components/Layout/PageLayout.tsx | 2 +- .../Popups/DeletePopUp/DeletePopUp.tsx | 2 +- .../Deduplication/index.tsx | 4 +- .../DeleteTabForOrphanNodes/index.tsx | 2 +- .../Popups/GraphEnhancementDialog/index.tsx | 2 +- .../Popups/LargeFilePopUp/LargeFilesAlert.tsx | 2 +- frontend/src/components/QuickStarter.tsx | 2 +- frontend/src/services/GetFiles.ts | 4 +- frontend/src/utils/Constants.ts | 4 +- 15 files changed, 85 insertions(+), 78 deletions(-) diff --git a/backend/src/QA_integration_new.py b/backend/src/QA_integration_new.py index 9ab42a497..eeac78c1e 100644 --- a/backend/src/QA_integration_new.py +++ b/backend/src/QA_integration_new.py @@ -41,7 +41,7 @@ def get_neo4j_retriever(graph, retrieval_query,document_names,mode,index_name="vector",keyword_index="keyword", search_k=CHAT_SEARCH_KWARG_K, score_threshold=CHAT_SEARCH_KWARG_SCORE_THRESHOLD): try: - if mode == "fulltext" or mode == "fulltext+graph": + if mode == "fulltext" or mode == "graph + vector + fulltext": neo_db = Neo4jVector.from_existing_graph( embedding=EMBEDDING_FUNCTION, index_name=index_name, diff --git a/frontend/src/API/Index.ts b/frontend/src/API/Index.ts index d086970e4..f4ad15cbe 100644 --- a/frontend/src/API/Index.ts +++ b/frontend/src/API/Index.ts @@ -1,7 +1,7 @@ -import axios from 'axios' -import { url } from '../utils/Utils' +import axios from 'axios'; +import { url } from '../utils/Utils'; -const api=axios.create({ - baseURL:url() -}) -export default api \ No newline at end of file +const api = axios.create({ + baseURL: url(), +}); +export default api; diff --git a/frontend/src/components/ChatBot/ChatModeToggle.tsx b/frontend/src/components/ChatBot/ChatModeToggle.tsx index 4c0d54bc7..e82dfea4d 100644 --- a/frontend/src/components/ChatBot/ChatModeToggle.tsx +++ b/frontend/src/components/ChatBot/ChatModeToggle.tsx @@ -31,7 +31,12 @@ export default function ChatModeToggle({ () => chatModes?.map((m) => { return { - title: capitalize(m), + title: m.includes('+') + ? m + .split('+') + .map((s) => capitalize(s)) + .join('+') + : capitalize(m), onClick: () => { setchatMode(m); }, diff --git a/frontend/src/components/Dropdown.tsx b/frontend/src/components/Dropdown.tsx index ed7c5fe6c..ba949aec0 100644 --- a/frontend/src/components/Dropdown.tsx +++ b/frontend/src/components/Dropdown.tsx @@ -13,7 +13,7 @@ const DropdownComponent: React.FC = ({ isDisabled, value, }) => { - const [disableTooltip, toggleDisableState] = useReducer((state)=>!state,false) + const [disableTooltip, toggleDisableState] = useReducer((state) => !state, false); const handleChange = (selectedOption: OptionType | null | void) => { onSelect(selectedOption); }; @@ -50,12 +50,12 @@ const DropdownComponent: React.FC = ({ menuPlacement: 'auto', isDisabled: isDisabled, value: value, - onMenuOpen:()=>{ - toggleDisableState() + onMenuOpen: () => { + toggleDisableState(); + }, + onMenuClose: () => { + toggleDisableState(); }, - onMenuClose:()=>{ - toggleDisableState() - } }} size='medium' fluid diff --git a/frontend/src/components/Graph/GraphViewModal.tsx b/frontend/src/components/Graph/GraphViewModal.tsx index ca407b4bb..39438b788 100644 --- a/frontend/src/components/Graph/GraphViewModal.tsx +++ b/frontend/src/components/Graph/GraphViewModal.tsx @@ -97,10 +97,10 @@ const GraphViewModal: React.FunctionComponent = ({ graphType.includes('DocumentChunk') && graphType.includes('Entities') ? queryMap.DocChunkEntities : graphType.includes('DocumentChunk') - ? queryMap.DocChunks - : graphType.includes('Entities') - ? queryMap.Entities - : ''; + ? queryMap.DocChunks + : graphType.includes('Entities') + ? queryMap.Entities + : ''; // fit graph to original position const handleZoomToFit = () => { @@ -135,10 +135,10 @@ const GraphViewModal: React.FunctionComponent = ({ const nodeRelationshipData = viewPoint === graphLabels.showGraphView ? await graphQueryAPI( - userCredentials as UserCredentials, - graphQuery, - selectedRows?.map((f) => f.name) - ) + userCredentials as UserCredentials, + graphQuery, + selectedRows?.map((f) => f.name) + ) : await graphQueryAPI(userCredentials as UserCredentials, graphQuery, [inspectedName ?? '']); return nodeRelationshipData; } catch (error: any) { @@ -196,43 +196,50 @@ const GraphViewModal: React.FunctionComponent = ({ }, [open]); // The search and update nodes - const handleSearch = useCallback((value: string) => { - const query = value.toLowerCase(); - const updatedNodes = nodes.map((node) => { - if (query === '') { + const handleSearch = useCallback( + (value: string) => { + const query = value.toLowerCase(); + const updatedNodes = nodes.map((node) => { + if (query === '') { + return { + ...node, + activated: false, + selected: false, + size: graphLabels.nodeSize, + }; + } + const { id, properties, caption } = node; + const propertiesMatch = properties?.id?.toLowerCase().includes(query); + const match = id.toLowerCase().includes(query) || propertiesMatch || caption?.toLowerCase().includes(query); return { ...node, + activated: match, + selected: match, + size: + match && viewPoint === graphLabels.showGraphView + ? 100 + : match && viewPoint !== graphLabels.showGraphView + ? 50 + : graphLabels.nodeSize, + }; + }); + // deactivating any active relationships + const updatedRelationships = relationships.map((rel) => { + return { + ...rel, activated: false, selected: false, - size: graphLabels.nodeSize }; - } - const { id, properties, caption } = node; - const propertiesMatch = properties?.id?.toLowerCase().includes(query); - const match = id.toLowerCase().includes(query) || propertiesMatch || caption?.toLowerCase().includes(query); - return { - ...node, - activated: match, - selected: match, - size: (match && viewPoint === graphLabels.showGraphView) ? 100 : (match && viewPoint !== graphLabels.showGraphView) ? 50 : graphLabels.nodeSize - }; - - }); - // deactivating any active relationships - const updatedRelationships = relationships.map((rel) => { - return { - ...rel, - activated: false, - selected: false, - }; - }); - setNodes(updatedNodes); - setRelationships(updatedRelationships); - }, [nodes]); + }); + setNodes(updatedNodes); + setRelationships(updatedRelationships); + }, + [nodes] + ); useEffect(() => { - handleSearch(debouncedQuery) - }, [debouncedQuery]) + handleSearch(debouncedQuery); + }, [debouncedQuery]); const initGraph = ( graphType: GraphType[], @@ -340,7 +347,12 @@ const GraphViewModal: React.FunctionComponent = ({ ...node, activated: isActive, selected: isActive, - size: (isActive && viewPoint === graphLabels.showGraphView) ? 100 : (isActive && viewPoint !== graphLabels.showGraphView) ? 50 : graphLabels.nodeSize + size: + isActive && viewPoint === graphLabels.showGraphView + ? 100 + : isActive && viewPoint !== graphLabels.showGraphView + ? 50 + : graphLabels.nodeSize, }; }); // deactivating any active relationships @@ -372,7 +384,7 @@ const GraphViewModal: React.FunctionComponent = ({ ...node, activated: false, selected: false, - size: graphLabels.nodeSize + size: graphLabels.nodeSize, }; }); if (searchQuery !== '') { @@ -568,4 +580,4 @@ const GraphViewModal: React.FunctionComponent = ({ ); }; -export default GraphViewModal; \ No newline at end of file +export default GraphViewModal; diff --git a/frontend/src/components/Graph/LegendsChip.tsx b/frontend/src/components/Graph/LegendsChip.tsx index 2fdc16df2..2ab9c7b40 100644 --- a/frontend/src/components/Graph/LegendsChip.tsx +++ b/frontend/src/components/Graph/LegendsChip.tsx @@ -1,14 +1,6 @@ import { LegendChipProps } from '../../types'; import Legend from '../UI/Legend'; -export const LegendsChip: React.FunctionComponent = ({ - scheme, - label, - type, - count, - onClick, -}) => { - return ( - - ); +export const LegendsChip: React.FunctionComponent = ({ scheme, label, type, count, onClick }) => { + return ; }; diff --git a/frontend/src/components/Layout/PageLayout.tsx b/frontend/src/components/Layout/PageLayout.tsx index 1a2f755b4..8aca58109 100644 --- a/frontend/src/components/Layout/PageLayout.tsx +++ b/frontend/src/components/Layout/PageLayout.tsx @@ -175,4 +175,4 @@ export default function PageLayoutNew({ />
); -} \ No newline at end of file +} diff --git a/frontend/src/components/Popups/DeletePopUp/DeletePopUp.tsx b/frontend/src/components/Popups/DeletePopUp/DeletePopUp.tsx index eb1522868..1b1bd58c8 100644 --- a/frontend/src/components/Popups/DeletePopUp/DeletePopUp.tsx +++ b/frontend/src/components/Popups/DeletePopUp/DeletePopUp.tsx @@ -54,4 +54,4 @@ export default function DeletePopUp({ ); -} \ No newline at end of file +} diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx index 36fcff3d1..f5a021e30 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx @@ -80,12 +80,12 @@ export default function DeduplicationTab() { const onRemove = (nodeid: string, similarNodeId: string) => { setDuplicateNodes((prev) => { return prev.map((d) => - d.e.elementId === nodeid + (d.e.elementId === nodeid ? { ...d, similar: d.similar.filter((n) => n.elementId != similarNodeId), } - : d + : d) ); }); }; diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx index f836c9e87..373007e95 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx @@ -279,4 +279,4 @@ export default function DeletePopUpForOrphanNodes({ ); -} \ No newline at end of file +} diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/index.tsx index 5e2aaf713..84577c53c 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/index.tsx @@ -126,4 +126,4 @@ export default function GraphEnhancementDialog({ ); -} \ No newline at end of file +} diff --git a/frontend/src/components/Popups/LargeFilePopUp/LargeFilesAlert.tsx b/frontend/src/components/Popups/LargeFilePopUp/LargeFilesAlert.tsx index b2eb01a52..26c9cfcda 100644 --- a/frontend/src/components/Popups/LargeFilePopUp/LargeFilesAlert.tsx +++ b/frontend/src/components/Popups/LargeFilePopUp/LargeFilesAlert.tsx @@ -100,4 +100,4 @@ const LargeFilesAlert: FC = ({ largeFiles, handleToggle, checke ); }; -export default LargeFilesAlert; \ No newline at end of file +export default LargeFilesAlert; diff --git a/frontend/src/components/QuickStarter.tsx b/frontend/src/components/QuickStarter.tsx index 29832fee1..db2cba7e7 100644 --- a/frontend/src/components/QuickStarter.tsx +++ b/frontend/src/components/QuickStarter.tsx @@ -42,4 +42,4 @@ const QuickStarter: React.FunctionComponent = () => {
); }; -export default QuickStarter; \ No newline at end of file +export default QuickStarter; diff --git a/frontend/src/services/GetFiles.ts b/frontend/src/services/GetFiles.ts index 0744ff047..056a9cc05 100644 --- a/frontend/src/services/GetFiles.ts +++ b/frontend/src/services/GetFiles.ts @@ -5,9 +5,7 @@ export const getSourceNodes = async (userCredentials: UserCredentials) => { try { const encodedstr = btoa(userCredentials.password); const response = await api.get( - `/sources_list?uri=${userCredentials.uri}&database=${userCredentials.database}&userName=${ - userCredentials.userName - }&password=${encodedstr}` + `/sources_list?uri=${userCredentials.uri}&database=${userCredentials.database}&userName=${userCredentials.userName}&password=${encodedstr}` ); return response; } catch (error) { diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index ee2296a3a..4222e8a7b 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -59,7 +59,7 @@ export const defaultLLM = llms?.includes('openai-gpt-4o-mini') export const chatModes = process.env?.VITE_CHAT_MODES?.trim() != '' ? process.env.VITE_CHAT_MODES?.split(',') - : ['vector', 'graph', 'graph+vector', 'fulltext', 'fulltext+graph']; + : ['vector', 'graph', 'graph+vector', 'fulltext', 'graph+vector+fulltext']; export const chunkSize = process.env.VITE_CHUNK_SIZE ? parseInt(process.env.VITE_CHUNK_SIZE) : 1 * 1024 * 1024; export const timeperpage = process.env.VITE_TIME_PER_PAGE ? parseInt(process.env.VITE_TIME_PER_PAGE) : 50; export const timePerByte = 0.2; @@ -232,7 +232,7 @@ export const graphLabels = { noEntities: 'No Entities Found', selectCheckbox: 'Select atleast one checkbox for graph view', totalRelationships: 'Total Relationships', - nodeSize: 30 + nodeSize: 30, }; export const RESULT_STEP_SIZE = 25; From 7d0b431728ce642cdbddc9c033b84b0b2c8c92f6 Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Thu, 22 Aug 2024 12:50:41 +0000 Subject: [PATCH 019/292] mode added to info model for entities --- frontend/src/components/ChatBot/ChatInfoModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index 42dad1893..25391b00e 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -175,7 +175,7 @@ const ChatInfoModal: React.FC = ({ ) : ( {mode != 'graph' ? Sources used : <>} - {mode === 'graph+vector' || mode === 'graph' ? Top Entities used : <>} + {mode === 'graph+vector' || mode === 'graph' || mode === 'graph+vector+fulltext' ? Top Entities used : <>} {mode === 'graph' && cypher_query?.trim().length ? ( Generated Cypher Query ) : ( From f2b1e172a70c8dfd63cda55007fa5ed4371e64a0 Mon Sep 17 00:00:00 2001 From: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Date: Mon, 26 Aug 2024 09:07:54 +0000 Subject: [PATCH 020/292] Issue fixed, List out of index while getting status of dicuement node --- backend/src/main.py | 160 +++++++++++++++++++++++--------------------- 1 file changed, 83 insertions(+), 77 deletions(-) diff --git a/backend/src/main.py b/backend/src/main.py index f7dd190ef..16eb0e622 100644 --- a/backend/src/main.py +++ b/backend/src/main.py @@ -277,91 +277,97 @@ def processing_source(uri, userName, password, database, model, file_name, pages create_chunks_obj = CreateChunksofDocument(pages, graph) chunks = create_chunks_obj.split_file_into_chunks() chunkId_chunkDoc_list = create_relation_between_chunks(graph,file_name,chunks) - if result[0]['Status'] != 'Processing': - obj_source_node = sourceNode() - status = "Processing" - obj_source_node.file_name = file_name - obj_source_node.status = status - obj_source_node.total_chunks = len(chunks) - obj_source_node.total_pages = len(pages) - obj_source_node.model = model - logging.info(file_name) - logging.info(obj_source_node) - graphDb_data_Access.update_source_node(obj_source_node) - - logging.info('Update the status as Processing') - update_graph_chunk_processed = int(os.environ.get('UPDATE_GRAPH_CHUNKS_PROCESSED')) - # selected_chunks = [] - is_cancelled_status = False - job_status = "Completed" - node_count = 0 - rel_count = 0 - for i in range(0, len(chunkId_chunkDoc_list), update_graph_chunk_processed): - select_chunks_upto = i+update_graph_chunk_processed - logging.info(f'Selected Chunks upto: {select_chunks_upto}') - if len(chunkId_chunkDoc_list) <= select_chunks_upto: - select_chunks_upto = len(chunkId_chunkDoc_list) - selected_chunks = chunkId_chunkDoc_list[i:select_chunks_upto] + + if len(result) > 0: + if result[0]['Status'] != 'Processing': + obj_source_node = sourceNode() + status = "Processing" + obj_source_node.file_name = file_name + obj_source_node.status = status + obj_source_node.total_chunks = len(chunks) + obj_source_node.total_pages = len(pages) + obj_source_node.model = model + logging.info(file_name) + logging.info(obj_source_node) + graphDb_data_Access.update_source_node(obj_source_node) + + logging.info('Update the status as Processing') + update_graph_chunk_processed = int(os.environ.get('UPDATE_GRAPH_CHUNKS_PROCESSED')) + # selected_chunks = [] + is_cancelled_status = False + job_status = "Completed" + node_count = 0 + rel_count = 0 + for i in range(0, len(chunkId_chunkDoc_list), update_graph_chunk_processed): + select_chunks_upto = i+update_graph_chunk_processed + logging.info(f'Selected Chunks upto: {select_chunks_upto}') + if len(chunkId_chunkDoc_list) <= select_chunks_upto: + select_chunks_upto = len(chunkId_chunkDoc_list) + selected_chunks = chunkId_chunkDoc_list[i:select_chunks_upto] + result = graphDb_data_Access.get_current_status_document_node(file_name) + is_cancelled_status = result[0]['is_cancelled'] + logging.info(f"Value of is_cancelled : {result[0]['is_cancelled']}") + if bool(is_cancelled_status) == True: + job_status = "Cancelled" + logging.info('Exit from running loop of processing file') + exit + else: + node_count,rel_count = processing_chunks(selected_chunks,graph,uri, userName, password, database,file_name,model,allowedNodes,allowedRelationship,node_count, rel_count) + end_time = datetime.now() + processed_time = end_time - start_time + + obj_source_node = sourceNode() + obj_source_node.file_name = file_name + obj_source_node.updated_at = end_time + obj_source_node.processing_time = processed_time + obj_source_node.node_count = node_count + obj_source_node.processed_chunk = select_chunks_upto + obj_source_node.relationship_count = rel_count + graphDb_data_Access.update_source_node(obj_source_node) + result = graphDb_data_Access.get_current_status_document_node(file_name) is_cancelled_status = result[0]['is_cancelled'] - logging.info(f"Value of is_cancelled : {result[0]['is_cancelled']}") if bool(is_cancelled_status) == True: - job_status = "Cancelled" - logging.info('Exit from running loop of processing file') - exit - else: - node_count,rel_count = processing_chunks(selected_chunks,graph,uri, userName, password, database,file_name,model,allowedNodes,allowedRelationship,node_count, rel_count) - end_time = datetime.now() - processed_time = end_time - start_time - - obj_source_node = sourceNode() - obj_source_node.file_name = file_name - obj_source_node.updated_at = end_time - obj_source_node.processing_time = processed_time - obj_source_node.node_count = node_count - obj_source_node.processed_chunk = select_chunks_upto - obj_source_node.relationship_count = rel_count - graphDb_data_Access.update_source_node(obj_source_node) - - result = graphDb_data_Access.get_current_status_document_node(file_name) - is_cancelled_status = result[0]['is_cancelled'] - if bool(is_cancelled_status) == True: - logging.info(f'Is_cancelled True at the end extraction') - job_status = 'Cancelled' - logging.info(f'Job Status at the end : {job_status}') - end_time = datetime.now() - processed_time = end_time - start_time - obj_source_node = sourceNode() - obj_source_node.file_name = file_name - obj_source_node.status = job_status - obj_source_node.processing_time = processed_time + logging.info(f'Is_cancelled True at the end extraction') + job_status = 'Cancelled' + logging.info(f'Job Status at the end : {job_status}') + end_time = datetime.now() + processed_time = end_time - start_time + obj_source_node = sourceNode() + obj_source_node.file_name = file_name + obj_source_node.status = job_status + obj_source_node.processing_time = processed_time - graphDb_data_Access.update_source_node(obj_source_node) - logging.info('Updated the nodeCount and relCount properties in Document node') - logging.info(f'file:{file_name} extraction has been completed') + graphDb_data_Access.update_source_node(obj_source_node) + logging.info('Updated the nodeCount and relCount properties in Document node') + logging.info(f'file:{file_name} extraction has been completed') - # merged_file_path have value only when file uploaded from local - - if is_uploaded_from_local: - gcs_file_cache = os.environ.get('GCS_FILE_CACHE') - if gcs_file_cache == 'True': - folder_name = create_gcs_bucket_folder_name_hashed(uri, file_name) - delete_file_from_gcs(BUCKET_UPLOAD,folder_name,file_name) - else: - delete_uploaded_local_file(merged_file_path, file_name) + # merged_file_path have value only when file uploaded from local - return { - "fileName": file_name, - "nodeCount": node_count, - "relationshipCount": rel_count, - "processingTime": round(processed_time.total_seconds(),2), - "status" : job_status, - "model" : model, - "success_count" : 1 - } + if is_uploaded_from_local: + gcs_file_cache = os.environ.get('GCS_FILE_CACHE') + if gcs_file_cache == 'True': + folder_name = create_gcs_bucket_folder_name_hashed(uri, file_name) + delete_file_from_gcs(BUCKET_UPLOAD,folder_name,file_name) + else: + delete_uploaded_local_file(merged_file_path, file_name) + + return { + "fileName": file_name, + "nodeCount": node_count, + "relationshipCount": rel_count, + "processingTime": round(processed_time.total_seconds(),2), + "status" : job_status, + "model" : model, + "success_count" : 1 + } + else: + logging.info('File does not process because it\'s already in Processing status') else: - logging.info('File does not process because it\'s already in Processing status') + error_message = "Unable to get the status of docuemnt node." + logging.error(error_message) + raise Exception(error_message) def processing_chunks(chunkId_chunkDoc_list,graph,uri, userName, password, database,file_name,model,allowedNodes,allowedRelationship, node_count, rel_count): #create vector index and update chunk node with embedding From 94c493eaef19386e07793f253aee578c54e44509 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Mon, 26 Aug 2024 11:55:36 +0000 Subject: [PATCH 021/292] processing count updated on cancel --- frontend/src/components/Content.tsx | 2 +- frontend/src/components/FileTable.tsx | 7 +++++++ frontend/src/hooks/useSse.tsx | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index ec4fad9bb..a1a1e69b1 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -381,7 +381,7 @@ const Content: React.FC = ({ setextractLoading(false); await postProcessing(userCredentials as UserCredentials, postProcessingTasks); }); - } else if (queueFiles && !queue.isEmpty()) { + } else if (queueFiles && !queue.isEmpty()&&processingFilesCount { setextractLoading(false); diff --git a/frontend/src/components/FileTable.tsx b/frontend/src/components/FileTable.tsx index 70dff8f1a..8c334a7b4 100644 --- a/frontend/src/components/FileTable.tsx +++ b/frontend/src/components/FileTable.tsx @@ -761,6 +761,13 @@ const FileTable = forwardRef((props, ref) => { return curfile; }) ); + setProcessedCount((prev) => { + if (prev == batchSize) { + return batchSize - 1; + } + return prev + 1; + }); + queue.remove(fileName) } else { let errorobj = { error: res.data.error, message: res.data.message, fileName }; throw new Error(JSON.stringify(errorobj)); diff --git a/frontend/src/hooks/useSse.tsx b/frontend/src/hooks/useSse.tsx index f8a07f61e..36be24c7b 100644 --- a/frontend/src/hooks/useSse.tsx +++ b/frontend/src/hooks/useSse.tsx @@ -45,7 +45,7 @@ export default function useServerSideEvent( }); }); } - } else if (status === 'Completed' || status === 'Cancelled') { + } else if (status === 'Completed') { setFilesData((prevfiles) => { return prevfiles.map((curfile) => { if (curfile.name == fileName) { From 3ef88b65492aee3c6fd9f1c0d70d4be424bb3869 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Tue, 27 Aug 2024 10:04:19 +0000 Subject: [PATCH 022/292] format fixes --- .../src/components/ChatBot/ChatInfoModal.tsx | 6 +++++- frontend/src/components/Content.tsx | 2 +- frontend/src/components/FileTable.tsx | 2 +- frontend/src/components/Graph/GraphViewModal.tsx | 16 ++++++++-------- .../Deduplication/index.tsx | 4 ++-- 5 files changed, 17 insertions(+), 13 deletions(-) diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index 25391b00e..89c15ea72 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -175,7 +175,11 @@ const ChatInfoModal: React.FC = ({ ) : ( {mode != 'graph' ? Sources used : <>} - {mode === 'graph+vector' || mode === 'graph' || mode === 'graph+vector+fulltext' ? Top Entities used : <>} + {mode === 'graph+vector' || mode === 'graph' || mode === 'graph+vector+fulltext' ? ( + Top Entities used + ) : ( + <> + )} {mode === 'graph' && cypher_query?.trim().length ? ( Generated Cypher Query ) : ( diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index a1a1e69b1..64945d5d5 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -381,7 +381,7 @@ const Content: React.FC = ({ setextractLoading(false); await postProcessing(userCredentials as UserCredentials, postProcessingTasks); }); - } else if (queueFiles && !queue.isEmpty()&&processingFilesCount { setextractLoading(false); diff --git a/frontend/src/components/FileTable.tsx b/frontend/src/components/FileTable.tsx index 8c334a7b4..23310eaf4 100644 --- a/frontend/src/components/FileTable.tsx +++ b/frontend/src/components/FileTable.tsx @@ -767,7 +767,7 @@ const FileTable = forwardRef((props, ref) => { } return prev + 1; }); - queue.remove(fileName) + queue.remove(fileName); } else { let errorobj = { error: res.data.error, message: res.data.message, fileName }; throw new Error(JSON.stringify(errorobj)); diff --git a/frontend/src/components/Graph/GraphViewModal.tsx b/frontend/src/components/Graph/GraphViewModal.tsx index 0c8153fe0..39438b788 100644 --- a/frontend/src/components/Graph/GraphViewModal.tsx +++ b/frontend/src/components/Graph/GraphViewModal.tsx @@ -97,10 +97,10 @@ const GraphViewModal: React.FunctionComponent = ({ graphType.includes('DocumentChunk') && graphType.includes('Entities') ? queryMap.DocChunkEntities : graphType.includes('DocumentChunk') - ? queryMap.DocChunks - : graphType.includes('Entities') - ? queryMap.Entities - : ''; + ? queryMap.DocChunks + : graphType.includes('Entities') + ? queryMap.Entities + : ''; // fit graph to original position const handleZoomToFit = () => { @@ -135,10 +135,10 @@ const GraphViewModal: React.FunctionComponent = ({ const nodeRelationshipData = viewPoint === graphLabels.showGraphView ? await graphQueryAPI( - userCredentials as UserCredentials, - graphQuery, - selectedRows?.map((f) => f.name) - ) + userCredentials as UserCredentials, + graphQuery, + selectedRows?.map((f) => f.name) + ) : await graphQueryAPI(userCredentials as UserCredentials, graphQuery, [inspectedName ?? '']); return nodeRelationshipData; } catch (error: any) { diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx index 36fcff3d1..f5a021e30 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx @@ -80,12 +80,12 @@ export default function DeduplicationTab() { const onRemove = (nodeid: string, similarNodeId: string) => { setDuplicateNodes((prev) => { return prev.map((d) => - d.e.elementId === nodeid + (d.e.elementId === nodeid ? { ...d, similar: d.similar.filter((n) => n.elementId != similarNodeId), } - : d + : d) ); }); }; From dadaa288c6302e7ba5b00915ba4468dbc568d4d3 Mon Sep 17 00:00:00 2001 From: edenbuaa Date: Tue, 27 Aug 2024 21:56:35 +0800 Subject: [PATCH 023/292] remove whitespace for enviroment variable which due to an error "xxx may not contain whitespace" (#707) --- example.env | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/example.env b/example.env index ed33101fb..23bcc6e06 100644 --- a/example.env +++ b/example.env @@ -1,27 +1,27 @@ # Mandatory -OPENAI_API_KEY = "" -DIFFBOT_API_KEY = "" +OPENAI_API_KEY="" +DIFFBOT_API_KEY="" # Optional Backend -EMBEDDING_MODEL = "all-MiniLM-L6-v2" -IS_EMBEDDING = "true" -KNN_MIN_SCORE = "0.94" +EMBEDDING_MODEL="all-MiniLM-L6-v2" +IS_EMBEDDING="true" +KNN_MIN_SCORE="0.94" # Enable Gemini (default is False) | Can be False or True -GEMINI_ENABLED = False +GEMINI_ENABLED=False # LLM_MODEL_CONFIG_ollama_llama3="llama3,http://host.docker.internal:11434" # Enable Google Cloud logs (default is False) | Can be False or True -GCP_LOG_METRICS_ENABLED = False -NUMBER_OF_CHUNKS_TO_COMBINE = 6 -UPDATE_GRAPH_CHUNKS_PROCESSED = 20 -NEO4J_URI = "neo4j://database:7687" -NEO4J_USERNAME = "neo4j" -NEO4J_PASSWORD = "password" -LANGCHAIN_API_KEY = "" -LANGCHAIN_PROJECT = "" -LANGCHAIN_TRACING_V2 = "true" -LANGCHAIN_ENDPOINT = "https://api.smith.langchain.com" -GCS_FILE_CACHE = False +GCP_LOG_METRICS_ENABLED=False +NUMBER_OF_CHUNKS_TO_COMBINE=6 +UPDATE_GRAPH_CHUNKS_PROCESSED=20 +NEO4J_URI="neo4j://database:7687" +NEO4J_USERNAME="neo4j" +NEO4J_PASSWORD="password" +LANGCHAIN_API_KEY="" +LANGCHAIN_PROJECT="" +LANGCHAIN_TRACING_V2="true" +LANGCHAIN_ENDPOINT="https://api.smith.langchain.com" +GCS_FILE_CACHE=False ENTITY_EMBEDDING=True # Optional Frontend From 4c6f676190a79159577112b3cd284c306d9ad146 Mon Sep 17 00:00:00 2001 From: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Date: Tue, 27 Aug 2024 15:06:45 +0000 Subject: [PATCH 024/292] updated disconnected nodes --- backend/Performance_test.py | 1 + backend/src/main.py | 1 + backend/test_integrationqa.py | 122 ++++++++++++++++++++++++++-------- 3 files changed, 96 insertions(+), 28 deletions(-) diff --git a/backend/Performance_test.py b/backend/Performance_test.py index fc0aee66f..712d3daf1 100644 --- a/backend/Performance_test.py +++ b/backend/Performance_test.py @@ -94,6 +94,7 @@ def performance_main(): for _ in range(CONCURRENT_REQUESTS): futures.append(executor.submit(post_request_chunk)) + # Chatbot request futures # Chatbot request futures # for message in CHATBOT_MESSAGES: # futures.append(executor.submit(chatbot_request, message)) diff --git a/backend/src/main.py b/backend/src/main.py index 16eb0e622..a7d5058a0 100644 --- a/backend/src/main.py +++ b/backend/src/main.py @@ -264,6 +264,7 @@ def processing_source(uri, userName, password, database, model, file_name, pages graphDb_data_Access = graphDBdataAccess(graph) result = graphDb_data_Access.get_current_status_document_node(file_name) + print(result) logging.info("Break down file into chunks") bad_chars = ['"', "\n", "'"] for i in range(0,len(pages)): diff --git a/backend/test_integrationqa.py b/backend/test_integrationqa.py index 20f3effb0..6f931058e 100644 --- a/backend/test_integrationqa.py +++ b/backend/test_integrationqa.py @@ -69,9 +69,7 @@ def test_graph_from_wikipedia(model_name): file_name = "Ram_Mandir" create_source_node_graph_url_wikipedia(graph, model_name, wiki_query, source_type) - wiki_result = extract_graph_from_file_Wikipedia( - URI, USERNAME, PASSWORD, DATABASE, model_name, file_name, 1, 'en', '', '' - ) + wiki_result = extract_graph_from_file_Wikipedia(URI, USERNAME, PASSWORD, DATABASE, model_name, file_name, 1, 'en', '', '') logging.info("Wikipedia test done") print(wiki_result) @@ -85,6 +83,27 @@ def test_graph_from_wikipedia(model_name): return wiki_result +def test_graph_website(model_name): + """Test graph creation from a Website page.""" + #graph, model, source_url, source_type + source_url = 'https://www.amazon.com/' + source_type = 'web-url' + create_source_node_graph_web_url(graph, model_name, source_url, source_type) + + weburl_result = extract_graph_from_web_page(URI, USERNAME, PASSWORD, DATABASE, model_name, source_url, '', '') + logging.info("WebUrl test done") + print(weburl_result) + + try: + assert weburl_result['status'] == 'Completed' + assert weburl_result['nodeCount'] > 0 + assert weburl_result['relationshipCount'] > 0 + print("Success") + except AssertionError as e: + print("Fail: ", e) + return weburl_result + + def test_graph_from_youtube_video(model_name): """Test graph creation from a YouTube video.""" source_url = 'https://www.youtube.com/watch?v=T-qy-zPWgqA' @@ -115,52 +134,99 @@ def test_chatbot_qna(model_name, mode='graph+vector'): try: assert len(QA_n_RAG['message']) > 20 + return QA_n_RAG + print("Success") + except AssertionError as e: + print("Failed ", e) + return QA_n_RAG + +# Check the Functionality of Chatbot QnA for mode 'vector' +def test_chatbot_QnA_vector(model_name): + model = model_name + QA_n_RAG_vector = QA_RAG(graph, model, 'Tell me about amazon', '[]', 1, 'vector') + + + print(QA_n_RAG_vector) + print(len(QA_n_RAG_vector['message'])) + try: + assert len(QA_n_RAG_vector['message']) > 20 + return QA_n_RAG_vector print("Success") except AssertionError as e: print("Failed: ", e) return QA_n_RAG -def compare_graph_results(results): - """ - Compare graph results across different models. - Add custom logic here to compare graph data, nodes, and relationships. - """ - # Placeholder logic for comparison - print("Comparing results...") - for i in range(len(results) - 1): - result_a = results[i] - result_b = results[i + 1] - if result_a == result_b: - print(f"Result {i} is identical to result {i+1}") +#Get disconnected_nodes list +def disconected_nodes(): + #graph = create_graph_database_connection(uri, userName, password, database) + graphDb_data_Access = graphDBdataAccess(graph) + nodes_list, total_nodes = graphDb_data_Access.list_unconnected_nodes() + if total_nodes['total']>0: + return "True" + else: + return "False" + +#Delete disconnected_nodes list +# def delete_disconected_nodes(): +# #graph = create_graph_database_connection(uri, userName, password, database) +# graphDb_data_Access = graphDBdataAccess(graph) +# result = graphDb_data_Access.delete_unconnected_nodes(unconnected_entities_list) + +#Get Duplicate_nodes +def get_duplicate_nodes(): + #graph = create_graph_database_connection(uri, userName, password, database) + graphDb_data_Access = graphDBdataAccess(graph) + nodes_list, total_nodes = graphDb_data_Access.get_duplicate_nodes_list() + if total_nodes['total']>0: + return "True" else: - print(f"Result {i} differs from result {i+1}") + return "False" + print(nodes_list) + print(total_nodes) + +# def compare_graph_results(results): +# """ +# Compare graph results across different models. +# Add custom logic here to compare graph data, nodes, and relationships. +# """ +# # Placeholder logic for comparison +# print("Comparing results...") +# for i in range(len(results) - 1): +# result_a = results[i] +# result_b = results[i + 1] +# if result_a == result_b: +# print(f"Result {i} is identical to result {i+1}") +# else: +# print(f"Result {i} differs from result {i+1}") def run_tests(): final_list = [] error_list = [] - models = [ - 'openai-gpt-3.5', 'openai-gpt-4o', 'openai-gpt-4o-mini', 'azure_ai_gpt_35', - 'azure_ai_gpt_4o', 'anthropic_claude_3_5_sonnet', 'fireworks_v3p1_405b', - 'fireworks_llama_v3_70b', 'ollama_llama3', 'bedrock_claude_3_5_sonnet' - ] + models = ['openai-gpt-3.5', 'openai-gpt-4o'] for model_name in models: try: - final_list.append(test_graph_from_file_local(model_name)) + # final_list.append(test_graph_from_file_local(model_name)) final_list.append(test_graph_from_wikipedia(model_name)) - final_list.append(test_graph_from_youtube_video(model_name)) - final_list.append(test_chatbot_qna(model_name)) - final_list.append(test_chatbot_qna(model_name, mode='vector')) - final_list.append(test_chatbot_qna(model_name, mode='hybrid')) + # final_list.append(test_graph_website(model_name)) + # final_list.append(test_graph_from_youtube_video(model_name)) + # final_list.append(test_chatbot_qna(model_name)) + # final_list.append(test_chatbot_qna(model_name, mode='vector')) + # final_list.append(test_chatbot_qna(model_name, mode='hybrid')) except Exception as e: error_list.append((model_name, str(e))) #Compare and log diffrences in graph results - compare_graph_results(final_list) # Pass the final_list to comapre_graph_results - + # compare_graph_results(final_list) # Pass the final_list to comapre_graph_results + + dis = disconected_nodes() + dup = get_duplicate_nodes() # Save final results to CSV df = pd.DataFrame(final_list) + print(df) df['execution_date'] = dt.today().strftime('%Y-%m-%d') + df['disconnected_nodes']=dis + df['get_duplicate_nodes']=dup df.to_csv(f"Integration_TestResult_{dt.now().strftime('%Y%m%d_%H%M%S')}.csv", index=False) # Save error details to CSV From 568db51c733e5b9cc140ea0d6aeaf0d63b842f52 Mon Sep 17 00:00:00 2001 From: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Date: Tue, 27 Aug 2024 15:11:14 +0000 Subject: [PATCH 025/292] updated disconnected nodes --- backend/test_integrationqa.py | 31 ++++++------------------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/backend/test_integrationqa.py b/backend/test_integrationqa.py index 6f931058e..b2222ebea 100644 --- a/backend/test_integrationqa.py +++ b/backend/test_integrationqa.py @@ -126,7 +126,7 @@ def test_graph_from_youtube_video(model_name): return youtube_result -def test_chatbot_qna(model_name, mode='graph+vector'): +def test_chatbot_qna(model_name, mode='vector'): """Test chatbot QnA functionality for different modes.""" QA_n_RAG = QA_RAG(graph, model_name, 'Tell me about amazon', '[]', 1, mode) print(QA_n_RAG) @@ -139,24 +139,7 @@ def test_chatbot_qna(model_name, mode='graph+vector'): except AssertionError as e: print("Failed ", e) return QA_n_RAG - -# Check the Functionality of Chatbot QnA for mode 'vector' -def test_chatbot_QnA_vector(model_name): - model = model_name - QA_n_RAG_vector = QA_RAG(graph, model, 'Tell me about amazon', '[]', 1, 'vector') - - - print(QA_n_RAG_vector) - print(len(QA_n_RAG_vector['message'])) - try: - assert len(QA_n_RAG_vector['message']) > 20 - return QA_n_RAG_vector - print("Success") - except AssertionError as e: - print("Failed: ", e) - - return QA_n_RAG - + #Get disconnected_nodes list def disconected_nodes(): #graph = create_graph_database_connection(uri, userName, password, database) @@ -182,8 +165,6 @@ def get_duplicate_nodes(): return "True" else: return "False" - print(nodes_list) - print(total_nodes) # def compare_graph_results(results): # """ @@ -208,12 +189,12 @@ def run_tests(): for model_name in models: try: # final_list.append(test_graph_from_file_local(model_name)) - final_list.append(test_graph_from_wikipedia(model_name)) - # final_list.append(test_graph_website(model_name)) + # final_list.append(test_graph_from_wikipedia(model_name)) + final_list.append(test_graph_website(model_name)) # final_list.append(test_graph_from_youtube_video(model_name)) - # final_list.append(test_chatbot_qna(model_name)) + final_list.append(test_chatbot_qna(model_name)) # final_list.append(test_chatbot_qna(model_name, mode='vector')) - # final_list.append(test_chatbot_qna(model_name, mode='hybrid')) + # final_list.append(test_chatbot_qna(model_name, mode='graph+vector+fulltext')) except Exception as e: error_list.append((model_name, str(e))) #Compare and log diffrences in graph results From 501ec6b741622282bd13c37d0713a2dfaccda78a Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Wed, 28 Aug 2024 05:02:20 +0000 Subject: [PATCH 026/292] fix: Processed count update on failed condition --- frontend/src/components/Content.tsx | 66 +++++++++++++++++++---------- frontend/src/hooks/useSse.tsx | 3 +- 2 files changed, 44 insertions(+), 25 deletions(-) diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 64945d5d5..039c04106 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -31,6 +31,8 @@ import FallBackDialog from './UI/FallBackDialog'; import DeletePopUp from './Popups/DeletePopUp/DeletePopUp'; import GraphEnhancementDialog from './Popups/GraphEnhancementDialog'; import { tokens } from '@neo4j-ndl/base'; +import axios from 'axios'; + const ConnectionModal = lazy(() => import('./Popups/ConnectionModal/ConnectionModal')); const ConfirmationDialog = lazy(() => import('./Popups/LargeFilePopUp/ConfirmationDialog')); let afterFirstRender = false; @@ -180,6 +182,7 @@ const Content: React.FC = ({ }; const extractHandler = async (fileItem: CustomFile, uid: string) => { + queue.remove(fileItem.name as string); try { setFilesData((prevfiles) => prevfiles.map((curfile) => { @@ -252,28 +255,45 @@ const Content: React.FC = ({ }); } } catch (err: any) { - const error = JSON.parse(err.message); - if (Object.keys(error).includes('fileName')) { - const { message } = error; - const { fileName } = error; - const errorMessage = error.message; - setalertDetails({ - showAlert: true, - alertType: 'error', - alertMessage: message, - }); - setFilesData((prevfiles) => - prevfiles.map((curfile) => { - if (curfile.name == fileName) { - return { - ...curfile, - status: 'Failed', - errorMessage, - }; - } - return curfile; - }) - ); + if (err instanceof Error) { + try { + const error = JSON.parse(err.message); + if (Object.keys(error).includes('fileName')) { + setProcessedCount((prev) => { + if (prev == batchSize) { + return batchSize - 1; + } + return prev + 1; + }); + const { message, fileName } = error; + queue.remove(fileName); + const errorMessage = error.message; + setalertDetails({ + showAlert: true, + alertType: 'error', + alertMessage: message, + }); + setFilesData((prevfiles) => + prevfiles.map((curfile) => { + if (curfile.name == fileName) { + return { ...curfile, status: 'Failed', errorMessage }; + } + return curfile; + }) + ); + } else { + console.error('Unexpected error format:', error); + } + } catch (parseError) { + if (axios.isAxiosError(err)) { + const axiosErrorMessage = err.response?.data?.message || err.message; + console.error('Axios error occurred:', axiosErrorMessage); + } else { + console.error('An unexpected error occurred:', err.message); + } + } + } else { + console.error('An unknown error occurred:', err); } } }; @@ -839,4 +859,4 @@ const Content: React.FC = ({ ); }; -export default Content; +export default Content; \ No newline at end of file diff --git a/frontend/src/hooks/useSse.tsx b/frontend/src/hooks/useSse.tsx index 36be24c7b..8b063751c 100644 --- a/frontend/src/hooks/useSse.tsx +++ b/frontend/src/hooks/useSse.tsx @@ -7,7 +7,7 @@ export default function useServerSideEvent( alertHandler: (inMinutes: boolean, minutes: number, filename: string) => void, errorHandler: (filename: string) => void ) { - const { setFilesData, setProcessedCount, queue } = useFileContext(); + const { setFilesData, setProcessedCount } = useFileContext(); function updateStatusForLargeFiles(eventSourceRes: eventResponsetypes) { const { fileName, @@ -67,7 +67,6 @@ export default function useServerSideEvent( } return prev + 1; }); - queue.remove(fileName); } else if (eventSourceRes.status === 'Failed') { setFilesData((prevfiles) => { return prevfiles.map((curfile) => { From 9941474aa0f213bd0afebcece2a70e4b8d275e0c Mon Sep 17 00:00:00 2001 From: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Date: Wed, 28 Aug 2024 11:23:03 +0000 Subject: [PATCH 027/292] added disconnected and up nodes --- backend/test_integrationqa.py | 42 ++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/backend/test_integrationqa.py b/backend/test_integrationqa.py index b2222ebea..4d0a5e1ea 100644 --- a/backend/test_integrationqa.py +++ b/backend/test_integrationqa.py @@ -1,3 +1,4 @@ +import json import os import shutil import logging @@ -145,16 +146,24 @@ def disconected_nodes(): #graph = create_graph_database_connection(uri, userName, password, database) graphDb_data_Access = graphDBdataAccess(graph) nodes_list, total_nodes = graphDb_data_Access.list_unconnected_nodes() + print(nodes_list[0]["e"]["elementId"]) + + status = "False" + if total_nodes['total']>0: - return "True" + status = "True" else: - return "False" + status = "False" + + return nodes_list[0]["e"]["elementId"], status #Delete disconnected_nodes list -# def delete_disconected_nodes(): -# #graph = create_graph_database_connection(uri, userName, password, database) -# graphDb_data_Access = graphDBdataAccess(graph) -# result = graphDb_data_Access.delete_unconnected_nodes(unconnected_entities_list) +def delete_disconected_nodes(lst_element_id): + print(f'disconnect elementid list {lst_element_id}') + #graph = create_graph_database_connection(uri, userName, password, database) + graphDb_data_Access = graphDBdataAccess(graph) + result = graphDb_data_Access.delete_unconnected_nodes(json.dumps(lst_element_id)) + print(f'delete disconnect api result {result}') #Get Duplicate_nodes def get_duplicate_nodes(): @@ -166,6 +175,11 @@ def get_duplicate_nodes(): else: return "False" +#Merge Duplicate_nodes +def test_merge_duplicate_nodes(): + graphDb_data_Access = graphDBdataAccess(graph) + result = graphDb_data_Access.merge_duplicate_nodes(duplicate_nodes_list) + # def compare_graph_results(results): # """ # Compare graph results across different models. @@ -188,25 +202,27 @@ def run_tests(): for model_name in models: try: - # final_list.append(test_graph_from_file_local(model_name)) - # final_list.append(test_graph_from_wikipedia(model_name)) + final_list.append(test_graph_from_file_local(model_name)) + final_list.append(test_graph_from_wikipedia(model_name)) final_list.append(test_graph_website(model_name)) - # final_list.append(test_graph_from_youtube_video(model_name)) + final_list.append(test_graph_from_youtube_video(model_name)) final_list.append(test_chatbot_qna(model_name)) - # final_list.append(test_chatbot_qna(model_name, mode='vector')) - # final_list.append(test_chatbot_qna(model_name, mode='graph+vector+fulltext')) + final_list.append(test_chatbot_qna(model_name, mode='vector')) + final_list.append(test_chatbot_qna(model_name, mode='graph+vector+fulltext')) except Exception as e: error_list.append((model_name, str(e))) #Compare and log diffrences in graph results # compare_graph_results(final_list) # Pass the final_list to comapre_graph_results - dis = disconected_nodes() + dis_elementid, dis_status = disconected_nodes() + lst_element_id = [dis_elementid] + delete_disconected_nodes(lst_element_id) dup = get_duplicate_nodes() # Save final results to CSV df = pd.DataFrame(final_list) print(df) df['execution_date'] = dt.today().strftime('%Y-%m-%d') - df['disconnected_nodes']=dis + df['disconnected_nodes']=dis_status df['get_duplicate_nodes']=dup df.to_csv(f"Integration_TestResult_{dt.now().strftime('%Y%m%d_%H%M%S')}.csv", index=False) From 8ae3b99d72edd456536e1a2b67a1f5d5f1b7d188 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Wed, 28 Aug 2024 17:15:49 +0000 Subject: [PATCH 028/292] removed __Entity__ labels --- backend/src/communities.py | 85 ++++++++++++++++++++++----------- backend/src/shared/common_fn.py | 4 +- 2 files changed, 58 insertions(+), 31 deletions(-) diff --git a/backend/src/communities.py b/backend/src/communities.py index b795ae4ed..e493a01dc 100644 --- a/backend/src/communities.py +++ b/backend/src/communities.py @@ -8,13 +8,37 @@ from tqdm import tqdm -COMMUNITY_PROJECT_NAME = "communities" -NODE_PROJECTION = "__Entity__" +COMMUNITY_PROJECTION_NAME = "communities" +NODE_PROJECTION = "!Chunk&!Document&!__Community__" MAX_WORKERS = 10 + +CREATE_COMMUNITY_GRAPH_PROJECTION = """ +MATCH (source:{node_projection}) +OPTIONAL MATCH (source)-[]->(target:{node_projection}) +WITH source, target, count(*) AS weight +WITH gds.graph.project( + {project_name}, + source, + target, + {{ + relationshipProperties: {{ weight: weight }} + }}, + {{ + undirectedRelationshipTypes: ['*'] + }} +) AS g +RETURN + g.graphName AS graph_name, + g.nodeCount AS nodes, + g.relationshipCount AS rels +""" + + CREATE_COMMUNITY_CONSTRAINT = "CREATE CONSTRAINT IF NOT EXISTS FOR (c:__Community__) REQUIRE c.id IS UNIQUE;" CREATE_COMMUNITY_LEVELS = """ -MATCH (e:`__Entity__`) +MATCH (e:!Chunk&!Document&!__Community__) +WHERE e.communities is NOT NULL UNWIND range(0, size(e.communities) - 1 , 1) AS index CALL { WITH e, index @@ -39,7 +63,7 @@ RETURN count(*) """ CREATE_COMMUNITY_RANKS = """ -MATCH (c:__Community__)<-[:IN_COMMUNITY*]-(:__Entity__)<-[:MENTIONS]-(d:Document) +MATCH (c:__Community__)<-[:IN_COMMUNITY*]-(:!Chunk&!Document&!__Community__)<-[:MENTIONS]-(d:Document) WITH c, count(distinct d) AS rank SET c.community_rank = rank; """ @@ -50,8 +74,7 @@ SET n.weight = chunkCount""" GET_COMMUNITY_INFO = """ -MATCH (c:`__Community__`)<-[:IN_COMMUNITY*]-(e:__Entity__) -WHERE c.level IN [0,1,4] +MATCH (c:`__Community__`)<-[:IN_COMMUNITY*]-(e:!Chunk&!Document&!__Community__) WITH c, collect(e ) AS nodes WHERE size(nodes) > 1 CALL apoc.path.subgraphAll(nodes[0], { @@ -90,39 +113,43 @@ def get_gds_driver(uri, username, password, database): logging.error(f"Failed to create GDS driver: {e}") raise -def create_community_graph_project(gds, project_name=COMMUNITY_PROJECT_NAME, node_projection=NODE_PROJECTION): +def create_community_graph_projection(gds, project_name=COMMUNITY_PROJECTION_NAME, node_projection=NODE_PROJECTION): try: existing_projects = gds.graph.list() project_exists = existing_projects["graphName"].str.contains(project_name, regex=False).any() if project_exists: - logging.info(f"Project '{project_name}' already exists. Dropping it.") + logging.info(f"Projection '{project_name}' already exists. Dropping it.") gds.graph.drop(project_name) logging.info(f"Creating new graph project '{project_name}'.") - graph_project, result = gds.graph.project( - project_name, - node_projection, - { - "_ALL_": { - "type": "*", - "orientation": "UNDIRECTED", - "properties": { - "weight": { - "property": "*", - "aggregation": "COUNT" - } - } - } - } - ) - logging.info(f"Graph project '{project_name}' created successfully.") - return graph_project, result + # graph_project, result = gds.graph.project( + # project_name, + # node_projection, + # { + # "_ALL_": { + # "type": "*", + # "orientation": "UNDIRECTED", + # "properties": { + # "weight": { + # "property": "*", + # "aggregation": "COUNT" + # } + # } + # } + # } + # ) + projection_query = CREATE_COMMUNITY_GRAPH_PROJECTION.format(node_projection=node_projection,project_name=project_name) + graph_projection_result = gds.run_cypher(projection_query) + projection_result = graph_projection_result.to_dict(orient="records")[0] + logging.info(f"Graph projection '{projection_result['graph_name']}' created successfully with {projection_result['nodes']} nodes and {projection_result['rels']} relationships.") + graph_project = gds.graph.get(projection_result['graph_name']) + return graph_project except Exception as e: logging.error(f"Failed to create community graph project: {e}") raise -def write_communities(gds, graph_project, project_name=COMMUNITY_PROJECT_NAME): +def write_communities(gds, graph_project, project_name=COMMUNITY_PROJECTION_NAME): try: logging.info(f"Writing communities to the graph project '{project_name}'.") gds.leiden.write( @@ -231,10 +258,10 @@ def create_community_properties(graph, model): logging.error(f"Failed to create community properties: {e}") raise -def create_communities(uri, username, password, database,graph,model): +def create_communities(uri, username, password, database,model): try: gds = get_gds_driver(uri, username, password, database) - graph_project, result = create_community_graph_project(gds) + graph_project = create_community_graph_projection(gds) write_communities_sucess = write_communities(gds, graph_project) if write_communities_sucess: logging.info("Applying community constraint to the graph.") diff --git a/backend/src/shared/common_fn.py b/backend/src/shared/common_fn.py index 6d24912c7..2037682e7 100644 --- a/backend/src/shared/common_fn.py +++ b/backend/src/shared/common_fn.py @@ -94,8 +94,8 @@ def load_embedding_model(embedding_model_name: str): return embeddings, dimension def save_graphDocuments_in_neo4j(graph:Neo4jGraph, graph_document_list:List[GraphDocument]): - graph.add_graph_documents(graph_document_list, baseEntityLabel=True,include_source=True) - # graph.add_graph_documents(graph_document_list) + # graph.add_graph_documents(graph_document_list, baseEntityLabel=True,include_source=True) + graph.add_graph_documents(graph_document_list) def handle_backticks_nodes_relationship_id_type(graph_document_list:List[GraphDocument]): for graph_document in graph_document_list: From 450ba6fd33ccf4d05a895a97a9df4228dde2816d Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Wed, 28 Aug 2024 17:56:57 +0000 Subject: [PATCH 029/292] removed graph_object --- backend/src/communities.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/backend/src/communities.py b/backend/src/communities.py index e493a01dc..cfbb1cc21 100644 --- a/backend/src/communities.py +++ b/backend/src/communities.py @@ -99,7 +99,6 @@ Summary:""" - def get_gds_driver(uri, username, password, database): try: gds = GraphDataScience( @@ -216,9 +215,9 @@ def process_community(community, community_chain): logging.error(f"Failed to process community {community.get('communityId', 'unknown')}: {e}") raise -def create_community_summaries(graph, model): +def create_community_summaries(gds, model): try: - community_info_list = graph.query(GET_COMMUNITY_INFO) + community_info_list = gds.run_cypher(GET_COMMUNITY_INFO) community_chain = get_community_chain(model) summaries = [] @@ -231,28 +230,28 @@ def create_community_summaries(graph, model): except Exception as e: logging.error(f"Failed to retrieve result for a community: {e}") - graph.query(STORE_COMMUNITY_SUMMARIES, params={"data": summaries}) + gds.run_cypher(STORE_COMMUNITY_SUMMARIES, params={"data": summaries}) except Exception as e: logging.error(f"Failed to create community summaries: {e}") raise -def create_community_properties(graph, model): +def create_community_properties(gds, model): try: # Create community levels - graph.query(CREATE_COMMUNITY_LEVELS) + gds.run_cypher(CREATE_COMMUNITY_LEVELS) logging.info("Successfully created community levels.") # Create community ranks - graph.query(CREATE_COMMUNITY_RANKS) + gds.run_cypher(CREATE_COMMUNITY_RANKS) logging.info("Successfully created community ranks.") # Create community weights - graph.query(CREATE_COMMUNITY_WEIGHTS) + gds.run_cypher(CREATE_COMMUNITY_WEIGHTS) logging.info("Successfully created community weights.") # Create community summaries - create_community_summaries(graph, model) + create_community_summaries(gds, model) logging.info("Successfully created community summaries.") except Exception as e: logging.error(f"Failed to create community properties: {e}") @@ -265,8 +264,8 @@ def create_communities(uri, username, password, database,model): write_communities_sucess = write_communities(gds, graph_project) if write_communities_sucess: logging.info("Applying community constraint to the graph.") - graph.query(CREATE_COMMUNITY_CONSTRAINT) - create_community_properties(graph,model) + gds.run_cypher(CREATE_COMMUNITY_CONSTRAINT) + create_community_properties(gds,model) logging.info("Communities creation process completed successfully.") else: logging.warning("Failed to write communities. Constraint was not applied.") From 266c8121883b29445ba0020f72038d1a99d0d30c Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Wed, 28 Aug 2024 18:02:49 +0000 Subject: [PATCH 030/292] removed graph object in the function --- backend/score.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/score.py b/backend/score.py index 717221520..7b06def44 100644 --- a/backend/score.py +++ b/backend/score.py @@ -244,7 +244,7 @@ async def post_processing(uri=Form(), userName=Form(), password=Form(), database if "create_communities" in tasks: model = "openai-gpt-4o" - await asyncio.to_thread(create_communities, uri, userName, password, database,graph,model) + await asyncio.to_thread(create_communities, uri, userName, password, database,model) josn_obj = {'api_name': 'post_processing/create_communities', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} logger.log_struct(josn_obj) logging.info(f'created communities') From cac1963d473ca9aa7c758336f1baefc465a4bd6e Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Thu, 29 Aug 2024 07:35:41 +0000 Subject: [PATCH 031/292] resetting the alert message on success scenario --- .../src/components/Popups/ConnectionModal/ConnectionModal.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx b/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx index 63e2d7883..a7b3fcb1f 100644 --- a/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx +++ b/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx @@ -266,6 +266,9 @@ export default function ConnectionModal({ } } setTimeout(() => { + if(connectionMessage?.type!="danger"){ + setMessage({ type: 'unknown', content: '' }) + } setPassword(''); }, 3000); }; From 43ec5691ff1729fc8936e5345bcc78ab2fadb8e0 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Thu, 29 Aug 2024 13:03:06 +0000 Subject: [PATCH 032/292] Modified queries --- backend/src/communities.py | 39 ++++++++++++++++------------------ backend/src/post_processing.py | 4 ++-- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/backend/src/communities.py b/backend/src/communities.py index cfbb1cc21..dbcb73ebc 100644 --- a/backend/src/communities.py +++ b/backend/src/communities.py @@ -16,25 +16,20 @@ CREATE_COMMUNITY_GRAPH_PROJECTION = """ MATCH (source:{node_projection}) OPTIONAL MATCH (source)-[]->(target:{node_projection}) -WITH source, target, count(*) AS weight +WITH source, target, count(*) as weight WITH gds.graph.project( - {project_name}, - source, - target, - {{ - relationshipProperties: {{ weight: weight }} - }}, - {{ - undirectedRelationshipTypes: ['*'] - }} -) AS g + '{project_name}', + source, + target, + {{ + relationshipProperties: {{ weight: weight }} + }}, + {{undirectedRelationshipTypes: ['*']}} + ) AS g RETURN - g.graphName AS graph_name, - g.nodeCount AS nodes, - g.relationshipCount AS rels + g.graphName AS graph_name, g.nodeCount AS nodes, g.relationshipCount AS rels """ - CREATE_COMMUNITY_CONSTRAINT = "CREATE CONSTRAINT IF NOT EXISTS FOR (c:__Community__) REQUIRE c.id IS UNIQUE;" CREATE_COMMUNITY_LEVELS = """ MATCH (e:!Chunk&!Document&!__Community__) @@ -63,7 +58,7 @@ RETURN count(*) """ CREATE_COMMUNITY_RANKS = """ -MATCH (c:__Community__)<-[:IN_COMMUNITY*]-(:!Chunk&!Document&!__Community__)<-[:MENTIONS]-(d:Document) +MATCH (c:__Community__)<-[:IN_COMMUNITY*]-(:!Chunk&!Document&!__Community__)<-[HAS_ENTITY]-(:Chunk)<-[]-(d:Document) WITH c, count(distinct d) AS rank SET c.community_rank = rank; """ @@ -74,8 +69,8 @@ SET n.weight = chunkCount""" GET_COMMUNITY_INFO = """ -MATCH (c:`__Community__`)<-[:IN_COMMUNITY*]-(e:!Chunk&!Document&!__Community__) -WITH c, collect(e ) AS nodes +MATCH (c:`__Community__`)<-[:IN_COMMUNITY]-(e) +WITH c, collect(e) AS nodes WHERE size(nodes) > 1 CALL apoc.path.subgraphAll(nodes[0], { whitelistNodes:nodes @@ -83,7 +78,7 @@ YIELD relationships RETURN c.id AS communityId, [n in nodes | {id: n.id, description: n.description, type: [el in labels(n) WHERE el <> '__Entity__'][0]}] AS nodes, - [r in relationships | {start: startNode(r).id, type: type(r), end: endNode(r).id, description: r.description}] AS rels + [r in relationships | {start: startNode(r).id, type: type(r), end: endNode(r).id}] AS rels """ STORE_COMMUNITY_SUMMARIES = """ @@ -200,7 +195,6 @@ def prepare_string(community_data): relationship_type = rel['type'] relationship_description = f", description: {rel['description']}" if 'description' in rel and rel['description'] else "" relationships_description += f"({start_node})-[:{relationship_type}]->({end_node}){relationship_description}\n" - return nodes_description + "\n" + relationships_description except Exception as e: logging.error(f"Failed to prepare string from community data: {e}") @@ -221,8 +215,11 @@ def create_community_summaries(gds, model): community_chain = get_community_chain(model) summaries = [] + futures = [] with ThreadPoolExecutor() as executor: - futures = {executor.submit(process_community, community, community_chain): community for community in community_info_list} + for _,community in community_info_list.iterrows(): + future = executor.submit(process_community, community, community_chain) + futures.append(future) for future in as_completed(futures): try: diff --git a/backend/src/post_processing.py b/backend/src/post_processing.py index fa582e107..7d038c61b 100644 --- a/backend/src/post_processing.py +++ b/backend/src/post_processing.py @@ -8,7 +8,7 @@ DROP_INDEX_QUERY = "DROP INDEX entities IF EXISTS;" LABELS_QUERY = "CALL db.labels()" FULL_TEXT_QUERY = "CREATE FULLTEXT INDEX entities FOR (n{labels_str}) ON EACH [n.id, n.description];" -FILTER_LABELS = ["Chunk","Document"] +FILTER_LABELS = ["Chunk","Document","__Community__"] HYBRID_SEARCH_INDEX_DROP_QUERY = "DROP INDEX keyword IF EXISTS;" @@ -80,7 +80,7 @@ def create_entity_embedding(graph:Neo4jGraph): def fetch_entities_for_embedding(graph): query = """ MATCH (e) - WHERE NOT (e:Chunk OR e:Document) AND e.embedding IS NULL AND e.id IS NOT NULL + WHERE NOT (e:Chunk OR e:Document OR e:`__Community__`) AND e.embedding IS NULL AND e.id IS NOT NULL RETURN elementId(e) AS elementId, e.id + " " + coalesce(e.description, "") AS text """ result = graph.query(query) From d010e419292bb94704bb5e2e6b464cc2d2cf40f1 Mon Sep 17 00:00:00 2001 From: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Date: Fri, 30 Aug 2024 11:00:27 +0000 Subject: [PATCH 033/292] populate graph schema --- backend/test_integrationqa.py | 48 ++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/backend/test_integrationqa.py b/backend/test_integrationqa.py index 4d0a5e1ea..821cc6b5c 100644 --- a/backend/test_integrationqa.py +++ b/backend/test_integrationqa.py @@ -141,13 +141,12 @@ def test_chatbot_qna(model_name, mode='vector'): print("Failed ", e) return QA_n_RAG -#Get disconnected_nodes list +#Get Test disconnected_nodes list def disconected_nodes(): #graph = create_graph_database_connection(uri, userName, password, database) graphDb_data_Access = graphDBdataAccess(graph) nodes_list, total_nodes = graphDb_data_Access.list_unconnected_nodes() print(nodes_list[0]["e"]["elementId"]) - status = "False" if total_nodes['total']>0: @@ -157,15 +156,19 @@ def disconected_nodes(): return nodes_list[0]["e"]["elementId"], status -#Delete disconnected_nodes list +#Test Delete delete_disconnected_nodes list def delete_disconected_nodes(lst_element_id): print(f'disconnect elementid list {lst_element_id}') #graph = create_graph_database_connection(uri, userName, password, database) graphDb_data_Access = graphDBdataAccess(graph) result = graphDb_data_Access.delete_unconnected_nodes(json.dumps(lst_element_id)) print(f'delete disconnect api result {result}') + if not result: + return "True" + else: + return "False" -#Get Duplicate_nodes +#Test Get Duplicate_nodes def get_duplicate_nodes(): #graph = create_graph_database_connection(uri, userName, password, database) graphDb_data_Access = graphDBdataAccess(graph) @@ -174,11 +177,12 @@ def get_duplicate_nodes(): return "True" else: return "False" - -#Merge Duplicate_nodes -def test_merge_duplicate_nodes(): - graphDb_data_Access = graphDBdataAccess(graph) - result = graphDb_data_Access.merge_duplicate_nodes(duplicate_nodes_list) + +#Test populate_graph_schema +def test_populate_graph_schema_from_text(model): + result_schema = populate_graph_schema_from_text('When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble.', model, True) + print(result_schema) + return result_schema # def compare_graph_results(results): # """ @@ -202,28 +206,32 @@ def run_tests(): for model_name in models: try: - final_list.append(test_graph_from_file_local(model_name)) - final_list.append(test_graph_from_wikipedia(model_name)) - final_list.append(test_graph_website(model_name)) - final_list.append(test_graph_from_youtube_video(model_name)) - final_list.append(test_chatbot_qna(model_name)) - final_list.append(test_chatbot_qna(model_name, mode='vector')) - final_list.append(test_chatbot_qna(model_name, mode='graph+vector+fulltext')) + final_list.append(test_graph_from_file_local(model_name)) + final_list.append(test_graph_from_wikipedia(model_name)) + final_list.append(test_populate_graph_schema_from_text(model_name)) + final_list.append(test_graph_website(model_name)) + final_list.append(test_graph_from_youtube_video(model_name)) + final_list.append(test_chatbot_qna(model_name)) + final_list.append(test_chatbot_qna(model_name, mode='vector')) + final_list.append(test_chatbot_qna(model_name, mode='graph+vector+fulltext')) except Exception as e: error_list.append((model_name, str(e))) - #Compare and log diffrences in graph results - # compare_graph_results(final_list) # Pass the final_list to comapre_graph_results - + # #Compare and log diffrences in graph results + # # compare_graph_results(final_list) # Pass the final_list to comapre_graph_results + # test_populate_graph_schema_from_text('openai-gpt-4o') dis_elementid, dis_status = disconected_nodes() lst_element_id = [dis_elementid] - delete_disconected_nodes(lst_element_id) + delt = delete_disconected_nodes(lst_element_id) dup = get_duplicate_nodes() + # schma = test_populate_graph_schema_from_text(model) # Save final results to CSV df = pd.DataFrame(final_list) print(df) df['execution_date'] = dt.today().strftime('%Y-%m-%d') df['disconnected_nodes']=dis_status df['get_duplicate_nodes']=dup + df['delete_disconected_nodes']=delt + # df['test_populate_graph_schema_from_text'] = schma df.to_csv(f"Integration_TestResult_{dt.now().strftime('%Y%m%d_%H%M%S')}.csv", index=False) # Save error details to CSV From b3a00aca7e9e3aa21edee9c78fec455edf012ef7 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Fri, 30 Aug 2024 13:20:01 +0000 Subject: [PATCH 034/292] not clearing the password when there is error scenario --- .../ConnectionModal/ConnectionModal.tsx | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx b/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx index a7b3fcb1f..e11509adf 100644 --- a/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx +++ b/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx @@ -197,6 +197,16 @@ export default function ConnectionModal({ if (response?.data?.status !== 'Success') { throw new Error(response.data.error); } else { + localStorage.setItem( + 'neo4j.connection', + JSON.stringify({ + uri: connectionURI, + user: username, + password: password, + database: database, + userDbVectorIndex, + }) + ); setUserDbVectorIndex(response.data.data.db_vector_dimension); if ( (response.data.data.application_dimension === response.data.data.db_vector_dimension || @@ -228,6 +238,7 @@ export default function ConnectionModal({ /> ), }); + return; } else { setMessage({ type: 'danger', @@ -244,17 +255,8 @@ export default function ConnectionModal({ /> ), }); + return; } - localStorage.setItem( - 'neo4j.connection', - JSON.stringify({ - uri: connectionURI, - user: username, - password: password, - database: database, - userDbVectorIndex, - }) - ); } } catch (error) { setIsLoading(false); From 77b06db1458345ff57a7e2aba2fc2ad04b805420 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Fri, 30 Aug 2024 13:49:00 +0000 Subject: [PATCH 035/292] fixed the vector index loading issue --- frontend/src/components/Content.tsx | 2 +- .../ConnectionModal/ConnectionModal.tsx | 20 +++++-------------- .../VectorIndexMisMatchAlert.tsx | 11 +++++++--- 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 039c04106..2dd6e1154 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -859,4 +859,4 @@ const Content: React.FC = ({ ); }; -export default Content; \ No newline at end of file +export default Content; diff --git a/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx b/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx index e11509adf..23d9a1481 100644 --- a/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx +++ b/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx @@ -104,7 +104,6 @@ export default function ConnectionModal({ type: 'danger', content: ( recreateVectorIndex(chunksExistsWithDifferentEmbedding)} isVectorIndexAlreadyExists={chunksExistsWithDifferentEmbedding || isVectorIndexMatch} userVectorIndexDimension={JSON.parse(localStorage.getItem('neo4j.connection') ?? 'null').userDbVectorIndex} @@ -113,7 +112,7 @@ export default function ConnectionModal({ ), }); } - }, [isVectorIndexMatch, vectorIndexLoading, chunksExistsWithDifferentEmbedding, chunksExistsWithoutEmbedding]); + }, [isVectorIndexMatch, chunksExistsWithDifferentEmbedding, chunksExistsWithoutEmbedding]); const parseAndSetURI = (uri: string, urlparams = false) => { const uriParts: string[] = uri.split('://'); @@ -224,15 +223,7 @@ export default function ConnectionModal({ type: 'danger', content: ( - recreateVectorIndex( - !( - response.data.data.db_vector_dimension > 0 && - response.data.data.db_vector_dimension != response.data.data.application_dimension - ) - ) - } + recreateVectorIndex={() => recreateVectorIndex(false)} isVectorIndexAlreadyExists={response.data.data.db_vector_dimension != 0} chunksExists={true} /> @@ -244,7 +235,6 @@ export default function ConnectionModal({ type: 'danger', content: ( recreateVectorIndex(true)} isVectorIndexAlreadyExists={ response.data.data.db_vector_dimension != 0 && @@ -268,9 +258,9 @@ export default function ConnectionModal({ } } setTimeout(() => { - if(connectionMessage?.type!="danger"){ - setMessage({ type: 'unknown', content: '' }) - } + if (connectionMessage?.type != 'danger') { + setMessage({ type: 'unknown', content: '' }); + } setPassword(''); }, 3000); }; diff --git a/frontend/src/components/Popups/ConnectionModal/VectorIndexMisMatchAlert.tsx b/frontend/src/components/Popups/ConnectionModal/VectorIndexMisMatchAlert.tsx index f9e85b63e..3c2965f44 100644 --- a/frontend/src/components/Popups/ConnectionModal/VectorIndexMisMatchAlert.tsx +++ b/frontend/src/components/Popups/ConnectionModal/VectorIndexMisMatchAlert.tsx @@ -2,21 +2,22 @@ import { Box, Flex } from '@neo4j-ndl/react'; import Markdown from 'react-markdown'; import ButtonWithToolTip from '../../UI/ButtonWithToolTip'; import { useCredentials } from '../../../context/UserCredentials'; +import { useState } from 'react'; export default function VectorIndexMisMatchAlert({ - vectorIndexLoading, recreateVectorIndex, isVectorIndexAlreadyExists, userVectorIndexDimension, chunksExists, }: { - vectorIndexLoading: boolean; recreateVectorIndex: () => Promise; isVectorIndexAlreadyExists: boolean; userVectorIndexDimension?: number; chunksExists: boolean; }) { const { userCredentials } = useCredentials(); + const [vectorIndexLoading, setVectorIndexLoading] = useState(false); + return ( @@ -42,7 +43,11 @@ To proceed, please choose one of the following options: label='creates the supported vector index' placement='top' loading={vectorIndexLoading} - onClick={() => recreateVectorIndex()} + onClick={async () => { + setVectorIndexLoading(true); + await recreateVectorIndex(); + setVectorIndexLoading(false); + }} className='!w-full' color='danger' disabled={userCredentials === null} From d1662909c6dac6194420b84c440986488648632c Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Fri, 30 Aug 2024 14:07:51 +0000 Subject: [PATCH 036/292] fix: empty credentials payload for recreate vector index api --- .../ConnectionModal/ConnectionModal.tsx | 81 ++++++++++--------- 1 file changed, 43 insertions(+), 38 deletions(-) diff --git a/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx b/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx index 23d9a1481..ab9fe2399 100644 --- a/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx +++ b/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx @@ -60,41 +60,43 @@ export default function ConnectionModal({ }, [open]); const recreateVectorIndex = useCallback( - async (isNewVectorIndex: boolean) => { - try { - setVectorIndexLoading(true); - const response = await createVectorIndex(userCredentials as UserCredentials, isNewVectorIndex); - setVectorIndexLoading(false); - if (response.data.status === 'Failed') { - throw new Error(response.data.error); - } else { - setMessage({ - type: 'success', - content: 'Successfully created the vector index', - }); - setConnectionStatus(true); - localStorage.setItem( - 'neo4j.connection', - JSON.stringify({ - uri: userCredentials?.uri, - user: userCredentials?.userName, - password: userCredentials?.password, - database: userCredentials?.database, - userDbVectorIndex: 384, - }) - ); - } - } catch (error) { - setVectorIndexLoading(false); - if (error instanceof Error) { - console.log('Error in recreating the vector index', error.message); - setMessage({ type: 'danger', content: error.message }); + async (isNewVectorIndex: boolean, usercredential: UserCredentials) => { + if (usercredential != null && Object.values(usercredential).length) { + try { + setVectorIndexLoading(true); + const response = await createVectorIndex(usercredential as UserCredentials, isNewVectorIndex); + setVectorIndexLoading(false); + if (response.data.status === 'Failed') { + throw new Error(response.data.error); + } else { + setMessage({ + type: 'success', + content: 'Successfully created the vector index', + }); + setConnectionStatus(true); + localStorage.setItem( + 'neo4j.connection', + JSON.stringify({ + uri: usercredential?.uri, + user: usercredential?.userName, + password: usercredential?.password, + database: usercredential?.database, + userDbVectorIndex: 384, + }) + ); + } + } catch (error) { + setVectorIndexLoading(false); + if (error instanceof Error) { + console.log('Error in recreating the vector index', error.message); + setMessage({ type: 'danger', content: error.message }); + } } + setTimeout(() => { + setMessage({ type: 'unknown', content: '' }); + setOpenConnection((prev) => ({ ...prev, openPopUp: false })); + }, 3000); } - setTimeout(() => { - setMessage({ type: 'unknown', content: '' }); - setOpenConnection((prev) => ({ ...prev, openPopUp: false })); - }, 3000); }, [userCredentials, userDbVectorIndex] ); @@ -104,7 +106,9 @@ export default function ConnectionModal({ type: 'danger', content: ( recreateVectorIndex(chunksExistsWithDifferentEmbedding)} + recreateVectorIndex={() => + recreateVectorIndex(chunksExistsWithDifferentEmbedding, userCredentials as UserCredentials) + } isVectorIndexAlreadyExists={chunksExistsWithDifferentEmbedding || isVectorIndexMatch} userVectorIndexDimension={JSON.parse(localStorage.getItem('neo4j.connection') ?? 'null').userDbVectorIndex} chunksExists={chunksExistsWithoutEmbedding} @@ -112,7 +116,7 @@ export default function ConnectionModal({ ), }); } - }, [isVectorIndexMatch, chunksExistsWithDifferentEmbedding, chunksExistsWithoutEmbedding]); + }, [isVectorIndexMatch, chunksExistsWithDifferentEmbedding, chunksExistsWithoutEmbedding, userCredentials]); const parseAndSetURI = (uri: string, urlparams = false) => { const uriParts: string[] = uri.split('://'); @@ -188,7 +192,8 @@ export default function ConnectionModal({ const submitConnection = async () => { const connectionURI = `${protocol}://${URI}${URI.split(':')[1] ? '' : `:${port}`}`; - setUserCredentials({ uri: connectionURI, userName: username, password: password, database: database, port: port }); + const credential = { uri: connectionURI, userName: username, password: password, database: database, port: port }; + setUserCredentials(credential); setIsLoading(true); try { const response = await connectAPI(connectionURI, username, password, database); @@ -223,7 +228,7 @@ export default function ConnectionModal({ type: 'danger', content: ( recreateVectorIndex(false)} + recreateVectorIndex={() => recreateVectorIndex(false, credential)} isVectorIndexAlreadyExists={response.data.data.db_vector_dimension != 0} chunksExists={true} /> @@ -235,7 +240,7 @@ export default function ConnectionModal({ type: 'danger', content: ( recreateVectorIndex(true)} + recreateVectorIndex={() => recreateVectorIndex(true, credential)} isVectorIndexAlreadyExists={ response.data.data.db_vector_dimension != 0 && response.data.data.db_vector_dimension != response.data.data.application_dimension From 088eda21f5f0ee553ddc955fad24f3c113adbfa9 Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Mon, 2 Sep 2024 16:51:26 +0530 Subject: [PATCH 037/292] chatbot status (#676) * chatbot status * connection status check for ASK button * refresh disable check * review comment resolved * format fixes --- frontend/src/components/ChatBot/Chatbot.tsx | 15 +++++++++++---- frontend/src/components/Content.tsx | 3 +-- frontend/src/components/Graph/GraphViewModal.tsx | 4 ++++ frontend/src/components/Layout/DrawerChatbot.tsx | 3 ++- frontend/src/components/Layout/PageLayout.tsx | 9 +++++++-- frontend/src/components/Layout/SideNav.tsx | 3 +++ .../Deduplication/index.tsx | 4 ++-- frontend/src/context/UserCredentials.tsx | 7 ++++++- frontend/src/types.ts | 4 ++++ 9 files changed, 40 insertions(+), 12 deletions(-) diff --git a/frontend/src/components/ChatBot/Chatbot.tsx b/frontend/src/components/ChatBot/Chatbot.tsx index da5aaaf29..448af0e7d 100644 --- a/frontend/src/components/ChatBot/Chatbot.tsx +++ b/frontend/src/components/ChatBot/Chatbot.tsx @@ -22,7 +22,14 @@ import FallBackDialog from '../UI/FallBackDialog'; const InfoModal = lazy(() => import('./ChatInfoModal')); const Chatbot: FC = (props) => { - const { messages: listMessages, setMessages: setListMessages, isLoading, isFullScreen, clear } = props; + const { + messages: listMessages, + setMessages: setListMessages, + isLoading, + isFullScreen, + clear, + connectionStatus, + } = props; const [inputMessage, setInputMessage] = useState(''); const [loading, setLoading] = useState(isLoading); const { userCredentials } = useCredentials(); @@ -289,7 +296,7 @@ const Chatbot: FC = (props) => { shape='square' size='x-large' source={ChatBotAvatar} - status='online' + status={connectionStatus ? 'online' : 'offline'} type='image' /> ) : ( @@ -299,7 +306,7 @@ const Chatbot: FC = (props) => { name='KM' shape='square' size='x-large' - status='online' + status={connectionStatus ? 'online' : 'offline'} type='image' /> )} @@ -415,7 +422,7 @@ const Chatbot: FC = (props) => { placement='top' text={`Query Documents in ${chatMode} mode`} type='submit' - disabled={loading} + disabled={loading || !connectionStatus} size='medium' > {buttonCaptions.ask} {selectedRows != undefined && selectedRows.length > 0 && `(${selectedRows.length})`} diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 2dd6e1154..44e7fd325 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -57,8 +57,7 @@ const Content: React.FC = ({ }); const [openGraphView, setOpenGraphView] = useState(false); const [inspectedName, setInspectedName] = useState(''); - const [connectionStatus, setConnectionStatus] = useState(false); - const { setUserCredentials, userCredentials } = useCredentials(); + const { setUserCredentials, userCredentials, connectionStatus, setConnectionStatus } = useCredentials(); const [showConfirmationModal, setshowConfirmationModal] = useState(false); const [extractLoading, setextractLoading] = useState(false); diff --git a/frontend/src/components/Graph/GraphViewModal.tsx b/frontend/src/components/Graph/GraphViewModal.tsx index 39438b788..4125c0d12 100644 --- a/frontend/src/components/Graph/GraphViewModal.tsx +++ b/frontend/src/components/Graph/GraphViewModal.tsx @@ -69,6 +69,7 @@ const GraphViewModal: React.FunctionComponent = ({ const [newScheme, setNewScheme] = useState({}); const [searchQuery, setSearchQuery] = useState(''); const debouncedQuery = useDebounce(searchQuery, 300); + const [disableRefresh, setDisableRefresh] = useState(false); // the checkbox selection const handleCheckboxChange = (graph: GraphType) => { @@ -165,6 +166,7 @@ const GraphViewModal: React.FunctionComponent = ({ setAllNodes(finalNodes); setAllRelationships(finalRels); setScheme(schemeVal); + setDisableRefresh(false); } else { setLoading(false); setStatus('danger'); @@ -292,6 +294,7 @@ const GraphViewModal: React.FunctionComponent = ({ // Refresh the graph with nodes and relations if file is processing const handleRefresh = () => { + setDisableRefresh(true); graphApi('refreshMode'); setGraphType(graphType); setNodes(nodes); @@ -455,6 +458,7 @@ const GraphViewModal: React.FunctionComponent = ({ text='Refresh graph' onClick={handleRefresh} placement='left' + disabled={disableRefresh} > diff --git a/frontend/src/components/Layout/DrawerChatbot.tsx b/frontend/src/components/Layout/DrawerChatbot.tsx index d08b2d8d1..3150e96a5 100644 --- a/frontend/src/components/Layout/DrawerChatbot.tsx +++ b/frontend/src/components/Layout/DrawerChatbot.tsx @@ -3,7 +3,7 @@ import Chatbot from '../ChatBot/Chatbot'; import { DrawerChatbotProps, Messages } from '../../types'; import { useMessageContext } from '../../context/UserMessages'; -const DrawerChatbot: React.FC = ({ isExpanded, clearHistoryData, messages }) => { +const DrawerChatbot: React.FC = ({ isExpanded, clearHistoryData, messages, connectionStatus }) => { const { setMessages } = useMessageContext(); const getIsLoading = (messages: Messages[]) => { @@ -19,6 +19,7 @@ const DrawerChatbot: React.FC = ({ isExpanded, clearHistoryD setMessages={setMessages} clear={clearHistoryData} isLoading={getIsLoading(messages)} + connectionStatus={connectionStatus} /> diff --git a/frontend/src/components/Layout/PageLayout.tsx b/frontend/src/components/Layout/PageLayout.tsx index 8aca58109..8361ad3cd 100644 --- a/frontend/src/components/Layout/PageLayout.tsx +++ b/frontend/src/components/Layout/PageLayout.tsx @@ -33,7 +33,7 @@ export default function PageLayoutNew({ const [shows3Modal, toggleS3Modal] = useReducer((s) => !s, false); const [showGCSModal, toggleGCSModal] = useReducer((s) => !s, false); const [showGenericModal, toggleGenericModal] = useReducer((s) => !s, false); - const { userCredentials } = useCredentials(); + const { userCredentials, connectionStatus } = useCredentials(); const toggleLeftDrawer = () => { if (largedesktops) { setIsLeftExpanded(!isLeftExpanded); @@ -156,7 +156,12 @@ export default function PageLayoutNew({ closeSettingModal={closeSettingModal} /> {showDrawerChatbot && ( - + )} = ({ position, @@ -43,6 +44,7 @@ const SideNav: React.FC = ({ const [chatModeAnchor, setchatModeAnchor] = useState(null); const [showChatMode, setshowChatMode] = useState(false); const largedesktops = useMediaQuery(`(min-width:1440px )`); + const { connectionStatus } = useCredentials(); const date = new Date(); useEffect(() => { @@ -249,6 +251,7 @@ const SideNav: React.FC = ({ messages={messages ?? []} setMessages={setMessages} isLoading={getIsLoading(messages ?? [])} + connectionStatus={connectionStatus} /> , diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx index f5a021e30..36fcff3d1 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx @@ -80,12 +80,12 @@ export default function DeduplicationTab() { const onRemove = (nodeid: string, similarNodeId: string) => { setDuplicateNodes((prev) => { return prev.map((d) => - (d.e.elementId === nodeid + d.e.elementId === nodeid ? { ...d, similar: d.similar.filter((n) => n.elementId != similarNodeId), } - : d) + : d ); }); }; diff --git a/frontend/src/context/UserCredentials.tsx b/frontend/src/context/UserCredentials.tsx index 20ed75ae5..af13ea371 100644 --- a/frontend/src/context/UserCredentials.tsx +++ b/frontend/src/context/UserCredentials.tsx @@ -1,4 +1,4 @@ -import { createContext, useState, useContext, FunctionComponent, ReactNode } from 'react'; +import { createContext, useState, useContext, FunctionComponent, ReactNode, useReducer } from 'react'; import { ContextProps, UserCredentials } from '../types'; type Props = { @@ -8,6 +8,8 @@ type Props = { export const UserConnection = createContext({ userCredentials: null, setUserCredentials: () => null, + connectionStatus: false, + setConnectionStatus: () => null, }); export const useCredentials = () => { const userCredentials = useContext(UserConnection); @@ -15,9 +17,12 @@ export const useCredentials = () => { }; const UserCredentialsWrapper: FunctionComponent = (props) => { const [userCredentials, setUserCredentials] = useState(null); + const [connectionStatus, setConnectionStatus] = useReducer((state) => !state, false); const value = { userCredentials, setUserCredentials, + connectionStatus, + setConnectionStatus, }; return {props.children}; }; diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 5bf076d10..2802a2d6b 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -247,6 +247,7 @@ export type ChatbotProps = { isLoading: boolean; clear?: boolean; isFullScreen?: boolean; + connectionStatus: boolean; }; export interface WikipediaModalTypes { hideModal: () => void; @@ -638,11 +639,14 @@ export interface DrawerChatbotProps { isExpanded: boolean; clearHistoryData: boolean; messages: Messages[]; + connectionStatus: boolean; } export interface ContextProps { userCredentials: UserCredentials | null; setUserCredentials: (UserCredentials: UserCredentials) => void; + connectionStatus: boolean; + setConnectionStatus: Dispatch>; } export interface MessageContextType { messages: Messages[] | []; From dbfe2a73752f951f2f7a5a570035d9b3e071cf3c Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Mon, 2 Sep 2024 17:19:37 +0000 Subject: [PATCH 038/292] added properties and modified to entity labels --- backend/src/communities.py | 243 ++++++++++++++++++++++++-------- backend/src/shared/common_fn.py | 4 +- 2 files changed, 190 insertions(+), 57 deletions(-) diff --git a/backend/src/communities.py b/backend/src/communities.py index dbcb73ebc..1c670fff1 100644 --- a/backend/src/communities.py +++ b/backend/src/communities.py @@ -3,19 +3,19 @@ from src.llm import get_llm from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser -from tqdm import tqdm from concurrent.futures import ThreadPoolExecutor, as_completed -from tqdm import tqdm +import os +from src.shared.common_fn import load_embedding_model COMMUNITY_PROJECTION_NAME = "communities" NODE_PROJECTION = "!Chunk&!Document&!__Community__" +NODE_PROJECTION_ENTITY = "__Entity__" MAX_WORKERS = 10 CREATE_COMMUNITY_GRAPH_PROJECTION = """ -MATCH (source:{node_projection}) -OPTIONAL MATCH (source)-[]->(target:{node_projection}) +MATCH (source:{node_projection})-[]->(target:{node_projection}) WITH source, target, count(*) as weight WITH gds.graph.project( '{project_name}', @@ -32,7 +32,7 @@ CREATE_COMMUNITY_CONSTRAINT = "CREATE CONSTRAINT IF NOT EXISTS FOR (c:__Community__) REQUIRE c.id IS UNIQUE;" CREATE_COMMUNITY_LEVELS = """ -MATCH (e:!Chunk&!Document&!__Community__) +MATCH (e:`__Entity__`) WHERE e.communities is NOT NULL UNWIND range(0, size(e.communities) - 1 , 1) AS index CALL { @@ -52,7 +52,7 @@ ON CREATE SET current.level = index MERGE (previous:`__Community__` {id: toString(index - 1) + '-' + toString(e.communities[index - 1])}) ON CREATE SET previous.level = index - 1 - MERGE (previous)-[:IN_COMMUNITY]->(current) + MERGE (previous)-[:PARENT_COMMUNITY]->(current) RETURN count(*) AS count_1 } RETURN count(*) @@ -63,13 +63,26 @@ SET c.community_rank = rank; """ +CREATE_PARENT_COMMUNITY_RANKS = """ +MATCH (c:__Community__)<-[:PARENT_COMMUNITY*]-(:__Community__)<-[:IN_COMMUNITY*]-(:!Chunk&!Document&!__Community__)<-[HAS_ENTITY]-(:Chunk)<-[]-(d:Document) +WITH c, count(distinct d) AS rank +SET c.community_rank = rank; +""" + CREATE_COMMUNITY_WEIGHTS = """ MATCH (n:`__Community__`)<-[:IN_COMMUNITY]-()<-[:HAS_ENTITY]-(c) WITH n, count(distinct c) AS chunkCount -SET n.weight = chunkCount""" +SET n.weight = chunkCount +""" +CREATE_PARENT_COMMUNITY_WEIGHTS = """ +MATCH (n:`__Community__`)<-[:PARENT_COMMUNITY*]-(:`__Community__`)<-[:IN_COMMUNITY]-()<-[:HAS_ENTITY]-(c) +WITH n, count(distinct c) AS chunkCount +SET n.weight = chunkCount +""" GET_COMMUNITY_INFO = """ MATCH (c:`__Community__`)<-[:IN_COMMUNITY]-(e) +WHERE c.level = 0 WITH c, collect(e) AS nodes WHERE size(nodes) > 1 CALL apoc.path.subgraphAll(nodes[0], { @@ -81,17 +94,64 @@ [r in relationships | {start: startNode(r).id, type: type(r), end: endNode(r).id}] AS rels """ +GET_PARENT_COMMUNITY_INFO = """ +MATCH (p:`__Community__`)<-[:PARENT_COMMUNITY*]-(c:`__Community__`) +WHERE p.summary is null and c.summary is not null +RETURN p.id as communityId, collect(c.summary) as texts +""" + + STORE_COMMUNITY_SUMMARIES = """ UNWIND $data AS row MERGE (c:__Community__ {id:row.community}) SET c.summary = row.summary """ +COMMUNITY_SYSTEM_TEMPLATE = "Given input triples, generate the information summary. No pre-amble." + COMMUNITY_TEMPLATE = """Based on the provided nodes and relationships that belong to the same graph community, generate a natural language summary of the provided information: {community_info} -Summary:""" +Summary:""" + +PARENT_COMMUNITY_SYSTEM_TEMPLATE = "Given an input list of community summaries, generate a summary of the information" + +PARENT_COMMUNITY_TEMPLATE = """Based on the provided list of community summaries that belong to the same graph community, +generate a natural language summary of the information.Include all the necessary information as possible +{community_info} + +Summary:""" + + +GET_COMMUNITY_DETAILS = """ +MATCH (c:`__Community__`) +WHERE c.embedding IS NULL AND c.summary IS NOT NULL +RETURN c.id as communityId, c.summary as text +""" + +WRITE_COMMUNITY_EMBEDDINGS = """ +UNWIND $rows AS row +MATCH (c) WHERE c.id = row.communityId +CALL db.create.setNodeVectorProperty(c, "embedding", row.embedding) +""" + +DROP_COMMUNITIES = "MATCH (c:`__Community__`) DETACH DELETE c" +DROP_COMMUNITY_PROPERTY = "MATCH (e:`__Entity__`) REMOVE e.communities" + + +ENTITY_VECTOR_INDEX_NAME = "entity_vector" +ENTITY_VECTOR_EMBEDDING_DIMENSION = 384 + +CREATE_ENTITY_VECTOR_INDEX = """ +CREATE VECTOR INDEX {index_name} IF NOT EXISTS FOR (e:__Entity__) ON e.embedding +OPTIONS {{ + indexConfig: {{ + `vector.dimensions`: {embedding_dimension}, + `vector.similarity_function`: 'cosine' + }} +}} +""" def get_gds_driver(uri, username, password, database): @@ -117,22 +177,6 @@ def create_community_graph_projection(gds, project_name=COMMUNITY_PROJECTION_NAM gds.graph.drop(project_name) logging.info(f"Creating new graph project '{project_name}'.") - # graph_project, result = gds.graph.project( - # project_name, - # node_projection, - # { - # "_ALL_": { - # "type": "*", - # "orientation": "UNDIRECTED", - # "properties": { - # "weight": { - # "property": "*", - # "aggregation": "COUNT" - # } - # } - # } - # } - # ) projection_query = CREATE_COMMUNITY_GRAPH_PROJECTION.format(node_projection=node_projection,project_name=project_name) graph_projection_result = gds.run_cypher(projection_query) projection_result = graph_projection_result.to_dict(orient="records")[0] @@ -159,14 +203,17 @@ def write_communities(gds, graph_project, project_name=COMMUNITY_PROJECTION_NAME return False -def get_community_chain(model, community_template=COMMUNITY_TEMPLATE): +def get_community_chain(model, is_parent=False,community_template=COMMUNITY_TEMPLATE,system_template=COMMUNITY_SYSTEM_TEMPLATE): try: + if is_parent: + community_template=PARENT_COMMUNITY_TEMPLATE + system_template= PARENT_COMMUNITY_SYSTEM_TEMPLATE llm, model_name = get_llm(model) community_prompt = ChatPromptTemplate.from_messages( [ ( "system", - "Given input triples, generate the information summary. No pre-amble.", + system_template, ), ("human", community_template), ] @@ -200,68 +247,154 @@ def prepare_string(community_data): logging.error(f"Failed to prepare string from community data: {e}") raise -def process_community(community, community_chain): +def process_community_info(community, chain, is_parent=False): try: - formatted_community_info = prepare_string(community) - summary = community_chain.invoke({'community_info': formatted_community_info}) + if is_parent: + combined_text = " ".join(f"Summary {i+1}: {summary}" for i, summary in enumerate(community.get("texts", []))) + else: + combined_text = prepare_string(community) + summary = chain.invoke({'community_info': combined_text}) return {"community": community['communityId'], "summary": summary} except Exception as e: logging.error(f"Failed to process community {community.get('communityId', 'unknown')}: {e}") - raise + return None def create_community_summaries(gds, model): try: community_info_list = gds.run_cypher(GET_COMMUNITY_INFO) community_chain = get_community_chain(model) - + summaries = [] - futures = [] with ThreadPoolExecutor() as executor: - for _,community in community_info_list.iterrows(): - future = executor.submit(process_community, community, community_chain) - futures.append(future) - + futures = [executor.submit(process_community_info, community, community_chain) for _, community in community_info_list.items()] + for future in as_completed(futures): - try: - summaries.append(future.result()) - except Exception as e: - logging.error(f"Failed to retrieve result for a community: {e}") + result = future.result() + if result: + summaries.append(result) + else: + logging.error("community summaries could not be processed.") gds.run_cypher(STORE_COMMUNITY_SUMMARIES, params={"data": summaries}) + + parent_community_info = gds.run_cypher(GET_PARENT_COMMUNITY_INFO) + parent_community_chain = get_community_chain(model, is_parent=True) + + parent_summaries = [] + with ThreadPoolExecutor() as executor: + futures = [executor.submit(process_community_info, community, parent_community_chain, is_parent=True) for _, community in parent_community_info.items()] + + for future in as_completed(futures): + result = future.result() + if result: + parent_summaries.append(result) + else: + logging.error("parent community summaries could not be processed.") + + gds.run_cypher(STORE_COMMUNITY_SUMMARIES, params={"data": parent_summaries}) + except Exception as e: logging.error(f"Failed to create community summaries: {e}") raise +def create_community_embeddings(gds): + try: + embedding_model = os.getenv('EMBEDDING_MODEL') + embeddings, dimension = load_embedding_model(embedding_model) + logging.info(f"Embedding model '{embedding_model}' loaded successfully.") + + logging.info("Fetching community details.") + rows = gds.run_cypher(GET_COMMUNITY_DETAILS) + rows = rows[['communityId', 'text']].to_dict(orient='records') + logging.info(f"Fetched {len(rows)} communities.") + + batch_size = 100 + for i in range(0, len(rows), batch_size): + batch_rows = rows[i:i+batch_size] + for row in batch_rows: + try: + row['embedding'] = embeddings.embed_query(row['text']) + except Exception as e: + logging.error(f"Failed to embed text for community ID {row['communityId']}: {e}") + row['embedding'] = None + + try: + logging.info("Writing embeddings to the database.") + gds.run_cypher(WRITE_COMMUNITY_EMBEDDINGS, params={'rows': batch_rows}) + logging.info("Embeddings written successfully.") + except Exception as e: + logging.error(f"Failed to write embeddings to the database: {e}") + continue + return dimension + except Exception as e: + logging.error(f"An error occurred during the community embedding process: {e}") +def create_entity_vector_index(gds, embedding_dimension=ENTITY_VECTOR_EMBEDDING_DIMENSION): + query = CREATE_ENTITY_VECTOR_INDEX.format( + index_name=ENTITY_VECTOR_INDEX_NAME, + embedding_dimension=embedding_dimension + ) + try: + logging.info(f"Running Cypher query to create entity vector index: {query}") + gds.run_cypher(query) + logging.info("Entity vector index created successfully.") + except Exception as e: + logging.error(f"Error occurred while creating entity vector index: {e}", exc_info=True) + def create_community_properties(gds, model): + commands = [ + (CREATE_COMMUNITY_CONSTRAINT, "created community constraint to the graph."), + (CREATE_COMMUNITY_LEVELS, "Successfully created community levels."), + (CREATE_COMMUNITY_RANKS, "Successfully created community ranks."), + (CREATE_PARENT_COMMUNITY_RANKS, "Successfully created parent community ranks."), + (CREATE_COMMUNITY_WEIGHTS, "Successfully created community weights."), + (CREATE_PARENT_COMMUNITY_WEIGHTS, "Successfully created parent community weights."), + ] try: - # Create community levels - gds.run_cypher(CREATE_COMMUNITY_LEVELS) - logging.info("Successfully created community levels.") + for command, message in commands: + gds.run_cypher(command) + logging.info(message) - # Create community ranks - gds.run_cypher(CREATE_COMMUNITY_RANKS) - logging.info("Successfully created community ranks.") - - # Create community weights - gds.run_cypher(CREATE_COMMUNITY_WEIGHTS) - logging.info("Successfully created community weights.") - - # Create community summaries create_community_summaries(gds, model) logging.info("Successfully created community summaries.") + + embedding_dimension = create_community_embeddings(gds) + logging.info("Successfully created community embeddings.") + + create_entity_vector_index(gds,embedding_dimension=embedding_dimension) + logging.info("Successfully created Entity Vector Index.") + except Exception as e: - logging.error(f"Failed to create community properties: {e}") + logging.error(f"Error during community properties creation: {e}") raise + +def clear_communities(gds): + try: + logging.info("Starting to clear communities.") + + logging.info("Dropping communities...") + gds.run_cypher(DROP_COMMUNITIES) + logging.info(f"Communities dropped successfully") + + logging.info("Dropping community property from entities...") + gds.run_cypher(DROP_COMMUNITY_PROPERTY) + logging.info(f"Community property dropped successfully") + + except Exception as e: + logging.error(f"An error occurred while clearing communities: {e}") + raise + + def create_communities(uri, username, password, database,model): try: gds = get_gds_driver(uri, username, password, database) + clear_communities(gds) + graph_project = create_community_graph_projection(gds) write_communities_sucess = write_communities(gds, graph_project) if write_communities_sucess: - logging.info("Applying community constraint to the graph.") - gds.run_cypher(CREATE_COMMUNITY_CONSTRAINT) + logging.info("Starting Community properties creation process.") create_community_properties(gds,model) logging.info("Communities creation process completed successfully.") else: diff --git a/backend/src/shared/common_fn.py b/backend/src/shared/common_fn.py index 2037682e7..6d24912c7 100644 --- a/backend/src/shared/common_fn.py +++ b/backend/src/shared/common_fn.py @@ -94,8 +94,8 @@ def load_embedding_model(embedding_model_name: str): return embeddings, dimension def save_graphDocuments_in_neo4j(graph:Neo4jGraph, graph_document_list:List[GraphDocument]): - # graph.add_graph_documents(graph_document_list, baseEntityLabel=True,include_source=True) - graph.add_graph_documents(graph_document_list) + graph.add_graph_documents(graph_document_list, baseEntityLabel=True,include_source=True) + # graph.add_graph_documents(graph_document_list) def handle_backticks_nodes_relationship_id_type(graph_document_list:List[GraphDocument]): for graph_document in graph_document_list: From 3d25d78cf68a35bb142074585ff7c36587fb35a9 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Tue, 3 Sep 2024 17:51:29 +0530 Subject: [PATCH 039/292] Post processing call after all files completion (#716) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Dev To STAGING (#532) * format fixes and graph schema indication fix * Update README.md * added chat modes variable in env updated the readme * spell fix * added the chat mode in env table * added the logos * fixed the overflow issues * removed the extra fix * Fixed specific scenario "when the text from schema closes it should reopen the previous modal" * readme changes * removed dev console logs * added new retrieval query (#533) * format fixes and tab rendering fix * fixed the setting modal reopen issue --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Dev (#535) * format fixes and graph schema indication fix * Update README.md * added chat modes variable in env updated the readme * spell fix * added the chat mode in env table * added the logos * fixed the overflow issues * removed the extra fix * Fixed specific scenario "when the text from schema closes it should reopen the previous modal" * readme changes * removed dev console logs * added new retrieval query (#533) * format fixes and tab rendering fix * fixed the setting modal reopen issue --------- Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Dev (#537) * format fixes and graph schema indication fix * Update README.md * added chat modes variable in env updated the readme * spell fix * added the chat mode in env table * added the logos * fixed the overflow issues * removed the extra fix * Fixed specific scenario "when the text from schema closes it should reopen the previous modal" * readme changes * removed dev console logs * added new retrieval query (#533) * format fixes and tab rendering fix * fixed the setting modal reopen issue --------- Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Fix typo: correct 'josn_obj' to 'json_obj' (#697) * Staging To Main (#495) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * Dev (#433) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env * DEV to STAGING (#461) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * DEV to STAGING (#462) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * added upload api * changed the dropzone error message * Dev to staging (#466) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env * added upload api * changed the dropzone error message --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * format fixes * Close connect when graph object is not none * Call garbage collector to release the menory * Change error message * Added driver config as user_agent * Updated doc for the LLM_MODELS and GCS_FILE_CACHE (#473) * Web URLs are user input (#475) * web url support backend * added the tabs for input source * user agent added for Neo4jGraph connection * Tab view for sources * extract handling for web ur's * initial input handling * chunk creation before processing * code structure * format fixes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * changed the regex for web and cancel button naming * changed the schema dropdown type * readme updates * PROD version fix * changed the alert message for gcs * Delete unconnected entities from DB (#482) * 457 add schema before generate graph (#478) * schema setting from generate graph * changes * changes * badge changes * bug fix * Fulltext index and Update similarity graph (#479) * added full_text index * added one common function for post_processing * post processing api * added tasks param * modifed logging * post processing changes --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Graph and vector search (#485) * Modified the retrival query * added the chatmode toggle component * Modified to vector search * Moved the templates to constants * added the icons * added chat modes * code structure changes * Intergrated the API changges * Modified retrieval queries,refactored code * API integration changes * added the score * order change * wording change * modified constants * added graph+vector * added the tooltips * Modified query * removed the graph mode * tooltip camel Case * added the icon and extern link for web source in the info modal * added the youtube link in the source used tab * format fixes * added the hoverable link --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Update InfoModal.tsx * removed hover from chunks * remove… * lint fixes * Fix typo: correct 'josn_obj' to 'json_obj' (#697) * Staging To Main (#495) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * Dev (#433) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env * DEV to STAGING (#461) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * DEV to STAGING (#462) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * added upload api * changed the dropzone error message * Dev to staging (#466) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env * added upload api * changed the dropzone error message --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * format fixes * Close connect when graph object is not none * Call garbage collector to release the menory * Change error message * Added driver config as user_agent * Updated doc for the LLM_MODELS and GCS_FILE_CACHE (#473) * Web URLs are user input (#475) * web url support backend * added the tabs for input source * user agent added for Neo4jGraph connection * Tab view for sources * extract handling for web ur's * initial input handling * chunk creation before processing * code structure * format fixes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * changed the regex for web and cancel button naming * changed the schema dropdown type * readme updates * PROD version fix * changed the alert message for gcs * Delete unconnected entities from DB (#482) * 457 add schema before generate graph (#478) * schema setting from generate graph * changes * changes * badge changes * bug fix * Fulltext index and Update similarity graph (#479) * added full_text index * added one common function for post_processing * post processing api * added tasks param * modifed logging * post processing changes --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Graph and vector search (#485) * Modified the retrival query * added the chatmode toggle component * Modified to vector search * Moved the templates to constants * added the icons * added chat modes * code structure changes * Intergrated the API changges * Modified retrieval queries,refactored code * API integration changes * added the score * order change * wording change * modified constants * added graph+vector * added the tooltips * Modified query * removed the graph mode * tooltip camel Case * added the icon and extern link for web source in the info modal * added the youtube link in the source used tab * format fixes * added the hoverable link --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Update InfoModal.tsx * removed hover from chunks * remove… * lint fixes * connection _check * Fix typo: correct 'josn_obj' to 'json_obj' (#697) * Staging To Main (#495) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * Dev (#433) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env * DEV to STAGING (#461) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * DEV to STAGING (#462) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * added upload api * changed the dropzone error message * Dev to staging (#466) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env * added upload api * changed the dropzone error message --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * format fixes * Close connect when graph object is not none * Call garbage collector to release the menory * Change error message * Added driver config as user_agent * Updated doc for the LLM_MODELS and GCS_FILE_CACHE (#473) * Web URLs are user input (#475) * web url support backend * added the tabs for input source * user agent added for Neo4jGraph connection * Tab view for sources * extract handling for web ur's * initial input handling * chunk creation before processing * code structure * format fixes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * changed the regex for web and cancel button naming * changed the schema dropdown type * readme updates * PROD version fix * changed the alert message for gcs * Delete unconnected entities from DB (#482) * 457 add schema before generate graph (#478) * schema setting from generate graph * changes * changes * badge changes * bug fix * Fulltext index and Update similarity graph (#479) * added full_text index * added one common function for post_processing * post processing api * added tasks param * modifed logging * post processing changes --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Graph and vector search (#485) * Modified the retrival query * added the chatmode toggle component * Modified to vector search * Moved the templates to constants * added the icons * added chat modes * code structure changes * Intergrated the API changges * Modified retrieval queries,refactored code * API integration changes * added the score * order change * wording change * modified constants * added graph+vector * added the tooltips * Modified query * removed the graph mode * tooltip camel Case * added the icon and extern link for web source in the info modal * added the youtube link in the source used tab * format fixes * added the hoverable link --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Update InfoModal.tsx * removed hover from chunks * remove… * lint fixes * connection _check * Dev (#701) * lint fixes * connection _check --------- Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> * Chatbot changes (#700) * added Hybrid search from graph * modified mode params * fixed issue delete entities return count * removed specified version due to dependency clashes between versions * updated script"integration test cases" * decreased the delay for pollintg API * Graph enhancements (#696) * relationship Changes * addition of relationship labels * onclick to nodes * node-highlight * Build fixex * slash docker change * deactivating previous node/relationshsips * lint fixes * class issue * search * search on basis of id / captions * debounce changes * class changes (#693) * legends highlight * search query reset * node size * changed chat mode names (#702) * DEV to STAGING (#703) * Chatbot changes (#700) * added Hybrid search from graph * modified mode params * fixed issue delete entities return count * removed specified version due to dependency clashes between versions * updated script"integration test cases" * decreased the delay for pollintg API * Graph enhancements (#696) * relationship Changes * addition of relationship labels * onclick to nodes * node-highlight * Build fixex * slash docker change * deactivating previous node/relationshsips * lint fixes * class issue * search * search on basis of id / captions * debounce changes * class changes (#693) * legends highlight * search query reset * node size * changed chat mode names (#702) --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Co-authored-by: Pravesh1988 Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> * env changes * used axios instance for network calls * disabled the toolip when dropdown is open state * format fixes + chat mode naming changes * mode added to info model for entities * Dev (#705) * connection _check * Fix typo: correct 'josn_obj' to 'json_obj' (#697) * Staging To Main (#495) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * Dev (#433) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env * DEV to STAGING (#461) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * DEV to STAGING (#462) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * added upload api * changed the dropzone error message * Dev to staging (#466) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env * added upload api * changed the dropzone error message --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * format fixes * Close connect when graph object is not none * Call garbage collector to release the menory * Change error message * Added driver config as user_agent * Updated doc for the LLM_MODELS and GCS_FILE_CACHE (#473) * Web URLs are user input (#475) * web url support backend * added the tabs for input source * user agent added for Neo4jGraph connection * Tab view for sources * extract handling for web ur's * initial input handling * chunk creation before processing * code structure * format fixes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * changed the regex for web and cancel button naming * changed the schema dropdown type * readme updates * PROD version fix * changed the alert message for gcs * Delete unconnected entities from DB (#482) * 457 add schema before generate graph (#478) * schema setting from generate graph * changes * changes * badge changes * bug fix * Fulltext index and Update similarity graph (#479) * added full_text index * added one common function for post_processing * post processing api * added tasks param * modifed logging * post processing changes --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Graph and vector search (#485) * Modified the retrival query * added the chatmode toggle component * Modified to vector search * Moved the templates to constants * added the icons * added chat modes * code structure changes * Intergrated the API changges * Modified retrieval queries,refactored code * API integration changes * added the score * order change * wording change * modified constants * added graph+vector * added the tooltips * Modified query * removed the graph mode * tooltip camel Case * added the icon and extern link for web source in the info modal * added the youtube link in the source used tab * format fixes * added the hoverable link --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Update InfoModal.tsx … * Issue fixed, List out of index while getting status of dicuement node * default modes in staging * processing count updated on cancel * processing count update fix on cancel * format fixes * remove whitespace for enviroment variable which due to an error "xxx may not contain whitespace" (#707) * updated disconnected nodes * updated disconnected nodes * fix: Processed count update on failed condition * added disconnected and up nodes * resetting the alert message on success scenario * populate graph schema * not clearing the password when there is error scenario * fixed the vector index loading issue * fix: empty credentials payload for recreate vector index api * invoking the post processing after all processing completion --------- Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: destiny966113 <90891243+destiny966113@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> Co-authored-by: Ikko Eltociear Ashimine Co-authored-by: Pravesh1988 Co-authored-by: edenbuaa --- README.md | 2 +- backend/Performance_test.py | 1 + backend/requirements.txt | 24 +- backend/score.py | 51 +- backend/src/QA_integration_new.py | 28 +- backend/src/main.py | 161 ++++--- backend/src/shared/constants.py | 2 +- backend/test_integrationqa.py | 439 ++++++++---------- example.env | 37 +- frontend/Dockerfile | 3 +- frontend/example.env | 1 - frontend/src/API/Index.ts | 7 + frontend/src/App.css | 11 +- .../src/components/ChatBot/ChatInfoModal.tsx | 19 +- .../src/components/ChatBot/ChatModeToggle.tsx | 7 +- .../src/components/ChatBot/Info/InfoModal.tsx | 13 +- frontend/src/components/Content.tsx | 74 +-- frontend/src/components/Dropdown.tsx | 11 +- frontend/src/components/FileTable.tsx | 7 + .../src/components/Graph/GraphViewModal.tsx | 290 ++++++++++-- frontend/src/components/Graph/LegendsChip.tsx | 10 +- .../ConnectionModal/ConnectionModal.tsx | 116 ++--- .../VectorIndexMisMatchAlert.tsx | 11 +- .../Deduplication/index.tsx | 2 +- .../DeleteTabForOrphanNodes/index.tsx | 2 +- frontend/src/components/QuickStarter.tsx | 2 +- frontend/src/components/UI/Legend.tsx | 14 +- frontend/src/components/UI/ShowAll.tsx | 38 ++ frontend/src/context/UsersFiles.tsx | 2 +- frontend/src/hooks/useSse.tsx | 5 +- frontend/src/services/CancelAPI.ts | 5 +- frontend/src/services/ChunkEntitiesInfo.ts | 5 +- frontend/src/services/CommonAPI.ts | 5 +- frontend/src/services/ConnectAPI.ts | 5 +- frontend/src/services/DeleteFiles.ts | 5 +- frontend/src/services/DeleteOrphanNodes.ts | 5 +- frontend/src/services/GetDuplicateNodes.ts | 5 +- frontend/src/services/GetFiles.ts | 9 +- .../src/services/GetNodeLabelsRelTypes.ts | 5 +- frontend/src/services/GetOrphanNodes.ts | 5 +- frontend/src/services/GraphQuery.ts | 5 +- frontend/src/services/HealthStatus.ts | 7 +- .../src/services/MergeDuplicateEntities.ts | 5 +- frontend/src/services/PollingAPI.ts | 9 +- frontend/src/services/PostProcessing.ts | 5 +- frontend/src/services/QnaAPI.ts | 7 +- frontend/src/services/SchemaFromTextAPI.ts | 5 +- frontend/src/services/URLScan.ts | 5 +- frontend/src/services/vectorIndexCreation.ts | 5 +- frontend/src/types.ts | 39 +- frontend/src/utils/Constants.ts | 10 +- frontend/src/utils/Utils.ts | 10 +- frontend/yarn.lock | 2 +- 53 files changed, 920 insertions(+), 638 deletions(-) create mode 100644 frontend/src/API/Index.ts create mode 100644 frontend/src/components/UI/ShowAll.tsx diff --git a/README.md b/README.md index 800721ec3..e0b59346d 100644 --- a/README.md +++ b/README.md @@ -149,7 +149,7 @@ Allow unauthenticated request : Yes | VITE_LLM_MODELS | Mandatory | diffbot,openai-gpt-3.5,openai-gpt-4o | Models available for selection on the frontend, used for entities extraction and Q&A | VITE_CHAT_MODES | Mandatory | vector,graph+vector,graph,hybrid | Chat modes available for Q&A | VITE_ENV | Mandatory | DEV or PROD | Environment variable for the app | -| VITE_TIME_PER_CHUNK | Optional | 4 | Time per chunk for processing | +| VITE_TIME_PER_PAGE | Optional | 50 | Time per page for processing | | VITE_CHUNK_SIZE | Optional | 5242880 | Size of each chunk of file for upload | | VITE_GOOGLE_CLIENT_ID | Optional | | Client ID for Google authentication | | GCS_FILE_CACHE | Optional | False | If set to True, will save the files to process into GCS. If set to False, will save the files locally | diff --git a/backend/Performance_test.py b/backend/Performance_test.py index fc0aee66f..712d3daf1 100644 --- a/backend/Performance_test.py +++ b/backend/Performance_test.py @@ -94,6 +94,7 @@ def performance_main(): for _ in range(CONCURRENT_REQUESTS): futures.append(executor.submit(post_request_chunk)) + # Chatbot request futures # Chatbot request futures # for message in CHATBOT_MESSAGES: # futures.append(executor.submit(chatbot_request, message)) diff --git a/backend/requirements.txt b/backend/requirements.txt index ab42a749d..46c57aea5 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -69,18 +69,18 @@ jsonpath-python==1.0.6 jsonpointer==2.4 json-repair==0.25.2 kiwisolver==1.4.5 -langchain==0.2.8 -langchain-aws==0.1.9 -langchain-anthropic==0.1.19 -langchain-fireworks==0.1.4 -langchain-google-genai==1.0.7 -langchain-community==0.2.7 -langchain-core==0.2.19 -langchain-experimental==0.0.62 -langchain-google-vertexai==1.0.6 -langchain-groq==0.1.6 -langchain-openai==0.1.14 -langchain-text-splitters==0.2.2 +langchain +langchain-aws +langchain-anthropic +langchain-fireworks +langchain-google-genai +langchain-community +langchain-core +langchain-experimental +langchain-google-vertexai +langchain-groq +langchain-openai +langchain-text-splitters langdetect==1.0.9 langsmith==0.1.83 layoutparser==0.3.4 diff --git a/backend/score.py b/backend/score.py index 7b06def44..19f7ddb1a 100644 --- a/backend/score.py +++ b/backend/score.py @@ -106,8 +106,8 @@ async def create_source_knowledge_graph_url( return create_api_response('Failed',message='source_type is other than accepted source') message = f"Source Node created successfully for source type: {source_type} and source: {source}" - josn_obj = {'api_name':'url_scan','db_url':uri,'url_scanned_file':lst_file_name, 'source_url':source_url, 'wiki_query':wiki_query, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(josn_obj) + json_obj = {'api_name':'url_scan','db_url':uri,'url_scanned_file':lst_file_name, 'source_url':source_url, 'wiki_query':wiki_query, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(json_obj) return create_api_response("Success",message=message,success_count=success_count,failed_count=failed_count,file_name=lst_file_name) except Exception as e: error_message = str(e) @@ -209,9 +209,9 @@ async def extract_knowledge_graph_from_file( else: logging.info(f'Deleted File Path: {merged_file_path} and Deleted File Name : {file_name}') delete_uploaded_local_file(merged_file_path,file_name) - josn_obj = {'message':message,'error_message':error_message, 'file_name': file_name,'status':'Failed','db_url':uri,'failed_count':1, 'source_type': source_type, 'source_url':source_url, 'wiki_query':wiki_query, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(josn_obj) - logging.exception(f'File Failed in extraction: {josn_obj}') + json_obj = {'message':message,'error_message':error_message, 'file_name': file_name,'status':'Failed','db_url':uri,'failed_count':1, 'source_type': source_type, 'source_url':source_url, 'wiki_query':wiki_query, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(json_obj) + logging.exception(f'File Failed in extraction: {json_obj}') return create_api_response('Failed', message=message + error_message[:100], error=error_message, file_name = file_name) finally: gc.collect() @@ -226,8 +226,8 @@ async def get_source_list(uri:str, userName:str, password:str, database:str=None if " " in uri: uri = uri.replace(" ","+") result = await asyncio.to_thread(get_source_list_from_graph,uri,userName,decoded_password,database) - josn_obj = {'api_name':'sources_list','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(josn_obj) + json_obj = {'api_name':'sources_list','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(json_obj) return create_api_response("Success",data=result) except Exception as e: job_status = "Failed" @@ -251,19 +251,20 @@ async def post_processing(uri=Form(), userName=Form(), password=Form(), database if "materialize_text_chunk_similarities" in tasks: await asyncio.to_thread(update_graph, graph) - josn_obj = {'api_name': 'post_processing/materialize_text_chunk_similarities', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(josn_obj) + json_obj = {'api_name': 'post_processing/update_similarity_graph', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(json_obj) logging.info(f'Updated KNN Graph') + if "enable_hybrid_search_and_fulltext_search_in_bloom" in tasks: await asyncio.to_thread(create_fulltext, uri=uri, username=userName, password=password, database=database,type="entities") - await asyncio.to_thread(create_fulltext, uri=uri, username=userName, password=password, database=database,type="keyword") + # await asyncio.to_thread(create_fulltext, uri=uri, username=userName, password=password, database=database,type="keyword") josn_obj = {'api_name': 'post_processing/enable_hybrid_search_and_fulltext_search_in_bloom', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} logger.log_struct(josn_obj) logging.info(f'Full Text index created') if os.environ.get('ENTITY_EMBEDDING','False').upper()=="TRUE" and "materialize_entity_similarities" in tasks: await asyncio.to_thread(create_entity_embedding, graph) - josn_obj = {'api_name': 'post_processing/materialize_entity_similarities', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(josn_obj) + json_obj = {'api_name': 'post_processing/create_entity_embedding', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(json_obj) logging.info(f'Entity Embeddings created') return create_api_response('Success', message='All tasks completed successfully') @@ -292,8 +293,8 @@ async def chat_bot(uri=Form(),model=Form(None),userName=Form(), password=Form(), logging.info(f"Total Response time is {total_call_time:.2f} seconds") result["info"]["response_time"] = round(total_call_time, 2) - josn_obj = {'api_name':'chat_bot','db_url':uri,'session_id':session_id, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(josn_obj) + json_obj = {'api_name':'chat_bot','db_url':uri,'session_id':session_id, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(json_obj) return create_api_response('Success',data=result) except Exception as e: job_status = "Failed" @@ -309,8 +310,8 @@ async def chunk_entities(uri=Form(),userName=Form(), password=Form(), chunk_ids= try: logging.info(f"URI: {uri}, Username: {userName}, chunk_ids: {chunk_ids}") result = await asyncio.to_thread(get_entities_from_chunkids,uri=uri, username=userName, password=password, chunk_ids=chunk_ids) - josn_obj = {'api_name':'chunk_entities','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(josn_obj) + json_obj = {'api_name':'chunk_entities','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(json_obj) return create_api_response('Success',data=result) except Exception as e: job_status = "Failed" @@ -337,8 +338,8 @@ async def graph_query( password=password, document_names=document_names ) - josn_obj = {'api_name':'graph_query','db_url':uri,'document_names':document_names, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(josn_obj) + json_obj = {'api_name':'graph_query','db_url':uri,'document_names':document_names, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(json_obj) return create_api_response('Success', data=result) except Exception as e: job_status = "Failed" @@ -387,8 +388,8 @@ async def upload_large_file_into_chunks(file:UploadFile = File(...), chunkNumber try: graph = create_graph_database_connection(uri, userName, password, database) result = await asyncio.to_thread(upload_file, graph, model, file, chunkNumber, totalChunks, originalname, uri, CHUNK_DIR, MERGED_DIR) - josn_obj = {'api_name':'upload','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(josn_obj) + json_obj = {'api_name':'upload','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(json_obj) if int(chunkNumber) == int(totalChunks): return create_api_response('Success',data=result, message='Source Node Created Successfully') else: @@ -409,8 +410,8 @@ async def get_structured_schema(uri=Form(), userName=Form(), password=Form(), da graph = create_graph_database_connection(uri, userName, password, database) result = await asyncio.to_thread(get_labels_and_relationtypes, graph) logging.info(f'Schema result from DB: {result}') - josn_obj = {'api_name':'schema','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(josn_obj) + json_obj = {'api_name':'schema','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(json_obj) return create_api_response('Success', data=result) except Exception as e: message="Unable to get the labels and relationtypes from neo4j database" @@ -478,8 +479,8 @@ async def delete_document_and_entities(uri=Form(), result, files_list_size = await asyncio.to_thread(graphDb_data_Access.delete_file_from_graph, filenames, source_types, deleteEntities, MERGED_DIR, uri) # entities_count = result[0]['deletedEntities'] if 'deletedEntities' in result[0] else 0 message = f"Deleted {files_list_size} documents with entities from database" - josn_obj = {'api_name':'delete_document_and_entities','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(josn_obj) + json_obj = {'api_name':'delete_document_and_entities','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(json_obj) return create_api_response('Success',message=message) except Exception as e: job_status = "Failed" @@ -635,4 +636,4 @@ async def merge_duplicate_nodes(uri=Form(), userName=Form(), password=Form(), da gc.collect() if __name__ == "__main__": - uvicorn.run(app) \ No newline at end of file + uvicorn.run(app) diff --git a/backend/src/QA_integration_new.py b/backend/src/QA_integration_new.py index 1c0bc254c..eeac78c1e 100644 --- a/backend/src/QA_integration_new.py +++ b/backend/src/QA_integration_new.py @@ -41,26 +41,26 @@ def get_neo4j_retriever(graph, retrieval_query,document_names,mode,index_name="vector",keyword_index="keyword", search_k=CHAT_SEARCH_KWARG_K, score_threshold=CHAT_SEARCH_KWARG_SCORE_THRESHOLD): try: - if mode == "hybrid": - # neo_db = Neo4jVector.from_existing_graph( - # embedding=EMBEDDING_FUNCTION, - # index_name=index_name, - # retrieval_query=retrieval_query, - # graph=graph, - # search_type="hybrid", - # node_label="Chunk", - # embedding_node_property="embedding", - # text_node_properties=["text"] - # # keyword_index_name=keyword_index - # ) - neo_db = Neo4jVector.from_existing_index( + if mode == "fulltext" or mode == "graph + vector + fulltext": + neo_db = Neo4jVector.from_existing_graph( embedding=EMBEDDING_FUNCTION, index_name=index_name, retrieval_query=retrieval_query, graph=graph, search_type="hybrid", + node_label="Chunk", + embedding_node_property="embedding", + text_node_properties=["text"], keyword_index_name=keyword_index ) + # neo_db = Neo4jVector.from_existing_index( + # embedding=EMBEDDING_FUNCTION, + # index_name=index_name, + # retrieval_query=retrieval_query, + # graph=graph, + # search_type="hybrid", + # keyword_index_name=keyword_index + # ) logging.info(f"Successfully retrieved Neo4jVector index '{index_name}' and keyword index '{keyword_index}'") else: neo_db = Neo4jVector.from_existing_index( @@ -374,7 +374,7 @@ def QA_RAG(graph, model, question, document_names,session_id, mode): "user": "chatbot" } return result - elif mode == "vector" or mode == "hybrid": + elif mode == "vector" or mode == "fulltext": retrieval_query = VECTOR_SEARCH_QUERY else: retrieval_query = VECTOR_GRAPH_SEARCH_QUERY.format(no_of_entites=VECTOR_GRAPH_SEARCH_ENTITY_LIMIT) diff --git a/backend/src/main.py b/backend/src/main.py index f7dd190ef..a7d5058a0 100644 --- a/backend/src/main.py +++ b/backend/src/main.py @@ -264,6 +264,7 @@ def processing_source(uri, userName, password, database, model, file_name, pages graphDb_data_Access = graphDBdataAccess(graph) result = graphDb_data_Access.get_current_status_document_node(file_name) + print(result) logging.info("Break down file into chunks") bad_chars = ['"', "\n", "'"] for i in range(0,len(pages)): @@ -277,91 +278,97 @@ def processing_source(uri, userName, password, database, model, file_name, pages create_chunks_obj = CreateChunksofDocument(pages, graph) chunks = create_chunks_obj.split_file_into_chunks() chunkId_chunkDoc_list = create_relation_between_chunks(graph,file_name,chunks) - if result[0]['Status'] != 'Processing': - obj_source_node = sourceNode() - status = "Processing" - obj_source_node.file_name = file_name - obj_source_node.status = status - obj_source_node.total_chunks = len(chunks) - obj_source_node.total_pages = len(pages) - obj_source_node.model = model - logging.info(file_name) - logging.info(obj_source_node) - graphDb_data_Access.update_source_node(obj_source_node) - - logging.info('Update the status as Processing') - update_graph_chunk_processed = int(os.environ.get('UPDATE_GRAPH_CHUNKS_PROCESSED')) - # selected_chunks = [] - is_cancelled_status = False - job_status = "Completed" - node_count = 0 - rel_count = 0 - for i in range(0, len(chunkId_chunkDoc_list), update_graph_chunk_processed): - select_chunks_upto = i+update_graph_chunk_processed - logging.info(f'Selected Chunks upto: {select_chunks_upto}') - if len(chunkId_chunkDoc_list) <= select_chunks_upto: - select_chunks_upto = len(chunkId_chunkDoc_list) - selected_chunks = chunkId_chunkDoc_list[i:select_chunks_upto] + + if len(result) > 0: + if result[0]['Status'] != 'Processing': + obj_source_node = sourceNode() + status = "Processing" + obj_source_node.file_name = file_name + obj_source_node.status = status + obj_source_node.total_chunks = len(chunks) + obj_source_node.total_pages = len(pages) + obj_source_node.model = model + logging.info(file_name) + logging.info(obj_source_node) + graphDb_data_Access.update_source_node(obj_source_node) + + logging.info('Update the status as Processing') + update_graph_chunk_processed = int(os.environ.get('UPDATE_GRAPH_CHUNKS_PROCESSED')) + # selected_chunks = [] + is_cancelled_status = False + job_status = "Completed" + node_count = 0 + rel_count = 0 + for i in range(0, len(chunkId_chunkDoc_list), update_graph_chunk_processed): + select_chunks_upto = i+update_graph_chunk_processed + logging.info(f'Selected Chunks upto: {select_chunks_upto}') + if len(chunkId_chunkDoc_list) <= select_chunks_upto: + select_chunks_upto = len(chunkId_chunkDoc_list) + selected_chunks = chunkId_chunkDoc_list[i:select_chunks_upto] + result = graphDb_data_Access.get_current_status_document_node(file_name) + is_cancelled_status = result[0]['is_cancelled'] + logging.info(f"Value of is_cancelled : {result[0]['is_cancelled']}") + if bool(is_cancelled_status) == True: + job_status = "Cancelled" + logging.info('Exit from running loop of processing file') + exit + else: + node_count,rel_count = processing_chunks(selected_chunks,graph,uri, userName, password, database,file_name,model,allowedNodes,allowedRelationship,node_count, rel_count) + end_time = datetime.now() + processed_time = end_time - start_time + + obj_source_node = sourceNode() + obj_source_node.file_name = file_name + obj_source_node.updated_at = end_time + obj_source_node.processing_time = processed_time + obj_source_node.node_count = node_count + obj_source_node.processed_chunk = select_chunks_upto + obj_source_node.relationship_count = rel_count + graphDb_data_Access.update_source_node(obj_source_node) + result = graphDb_data_Access.get_current_status_document_node(file_name) is_cancelled_status = result[0]['is_cancelled'] - logging.info(f"Value of is_cancelled : {result[0]['is_cancelled']}") if bool(is_cancelled_status) == True: - job_status = "Cancelled" - logging.info('Exit from running loop of processing file') - exit - else: - node_count,rel_count = processing_chunks(selected_chunks,graph,uri, userName, password, database,file_name,model,allowedNodes,allowedRelationship,node_count, rel_count) - end_time = datetime.now() - processed_time = end_time - start_time - - obj_source_node = sourceNode() - obj_source_node.file_name = file_name - obj_source_node.updated_at = end_time - obj_source_node.processing_time = processed_time - obj_source_node.node_count = node_count - obj_source_node.processed_chunk = select_chunks_upto - obj_source_node.relationship_count = rel_count - graphDb_data_Access.update_source_node(obj_source_node) - - result = graphDb_data_Access.get_current_status_document_node(file_name) - is_cancelled_status = result[0]['is_cancelled'] - if bool(is_cancelled_status) == True: - logging.info(f'Is_cancelled True at the end extraction') - job_status = 'Cancelled' - logging.info(f'Job Status at the end : {job_status}') - end_time = datetime.now() - processed_time = end_time - start_time - obj_source_node = sourceNode() - obj_source_node.file_name = file_name - obj_source_node.status = job_status - obj_source_node.processing_time = processed_time + logging.info(f'Is_cancelled True at the end extraction') + job_status = 'Cancelled' + logging.info(f'Job Status at the end : {job_status}') + end_time = datetime.now() + processed_time = end_time - start_time + obj_source_node = sourceNode() + obj_source_node.file_name = file_name + obj_source_node.status = job_status + obj_source_node.processing_time = processed_time - graphDb_data_Access.update_source_node(obj_source_node) - logging.info('Updated the nodeCount and relCount properties in Document node') - logging.info(f'file:{file_name} extraction has been completed') + graphDb_data_Access.update_source_node(obj_source_node) + logging.info('Updated the nodeCount and relCount properties in Document node') + logging.info(f'file:{file_name} extraction has been completed') - # merged_file_path have value only when file uploaded from local - - if is_uploaded_from_local: - gcs_file_cache = os.environ.get('GCS_FILE_CACHE') - if gcs_file_cache == 'True': - folder_name = create_gcs_bucket_folder_name_hashed(uri, file_name) - delete_file_from_gcs(BUCKET_UPLOAD,folder_name,file_name) - else: - delete_uploaded_local_file(merged_file_path, file_name) + # merged_file_path have value only when file uploaded from local - return { - "fileName": file_name, - "nodeCount": node_count, - "relationshipCount": rel_count, - "processingTime": round(processed_time.total_seconds(),2), - "status" : job_status, - "model" : model, - "success_count" : 1 - } + if is_uploaded_from_local: + gcs_file_cache = os.environ.get('GCS_FILE_CACHE') + if gcs_file_cache == 'True': + folder_name = create_gcs_bucket_folder_name_hashed(uri, file_name) + delete_file_from_gcs(BUCKET_UPLOAD,folder_name,file_name) + else: + delete_uploaded_local_file(merged_file_path, file_name) + + return { + "fileName": file_name, + "nodeCount": node_count, + "relationshipCount": rel_count, + "processingTime": round(processed_time.total_seconds(),2), + "status" : job_status, + "model" : model, + "success_count" : 1 + } + else: + logging.info('File does not process because it\'s already in Processing status') else: - logging.info('File does not process because it\'s already in Processing status') + error_message = "Unable to get the status of docuemnt node." + logging.error(error_message) + raise Exception(error_message) def processing_chunks(chunkId_chunkDoc_list,graph,uri, userName, password, database,file_name,model,allowedNodes,allowedRelationship, node_count, rel_count): #create vector index and update chunk node with embedding diff --git a/backend/src/shared/constants.py b/backend/src/shared/constants.py index 903999a51..c5f8e98a4 100644 --- a/backend/src/shared/constants.py +++ b/backend/src/shared/constants.py @@ -276,4 +276,4 @@ RETURN text, avg_score as score, {{length:size(text), source: COALESCE( CASE WHEN d.url CONTAINS "None" THEN d.fileName ELSE d.url END, d.fileName), chunkdetails: chunkdetails}} AS metadata """ -YOUTUBE_CHUNK_SIZE_SECONDS = 60 \ No newline at end of file +YOUTUBE_CHUNK_SIZE_SECONDS = 60 diff --git a/backend/test_integrationqa.py b/backend/test_integrationqa.py index cd662cbdc..821cc6b5c 100644 --- a/backend/test_integrationqa.py +++ b/backend/test_integrationqa.py @@ -1,270 +1,243 @@ +import json +import os +import shutil +import logging +import pandas as pd +from datetime import datetime as dt +from dotenv import load_dotenv + from score import * from src.main import * -import logging from src.QA_integration_new import QA_RAG from langserve import add_routes -import asyncio -import os -from dotenv import load_dotenv -import pandas as pd -from datetime import datetime as dt -uri = '' -userName = '' -password = '' -# model = 'openai-gpt-3.5' -database = 'neo4j' +# Load environment variables if needed +load_dotenv() + +# Constants +URI = '' +USERNAME = '' +PASSWORD = '' +DATABASE = 'neo4j' CHUNK_DIR = os.path.join(os.path.dirname(__file__), "chunks") MERGED_DIR = os.path.join(os.path.dirname(__file__), "merged_files") -graph = create_graph_database_connection(uri, userName, password, database) - - -def test_graph_from_file_local_file(model_name): - model = model_name - file_name = 'About Amazon.pdf' - # shutil.copyfile('data/Bank of America Q23.pdf', 'backend/src/merged_files/Bank of America Q23.pdf') - shutil.copyfile('/workspaces/llm-graph-builder/backend/files/About Amazon.pdf', - '/workspaces/llm-graph-builder/backend/merged_files/About Amazon.pdf') - obj_source_node = sourceNode() - obj_source_node.file_name = file_name - obj_source_node.file_type = 'pdf' - obj_source_node.file_size = '1087' - obj_source_node.file_source = 'local file' - obj_source_node.model = model - obj_source_node.created_at = datetime.now() - graphDb_data_Access = graphDBdataAccess(graph) - graphDb_data_Access.create_source_node(obj_source_node) - merged_file_path = os.path.join(MERGED_DIR, file_name) - print(merged_file_path) - - - local_file_result = extract_graph_from_file_local_file(uri, userName, password, database, model, merged_file_path, file_name, '', '') - # final_list.append(local_file_result) - print(local_file_result) - - logging.info("Info: ") - try: - assert local_file_result['status'] == 'Completed' and local_file_result['nodeCount'] > 0 and local_file_result[ - 'relationshipCount'] > 0 - return local_file_result - print("Success") - except AssertionError as e: - print("Fail: ", e) - return local_file_result - - -def test_graph_from_file_local_file_failed(model_name): - model = model_name - file_name = 'Not_exist.pdf' - try: - obj_source_node = sourceNode() - obj_source_node.file_name = file_name - obj_source_node.file_type = 'pdf' - obj_source_node.file_size = '0' - obj_source_node.file_source = 'local file' - obj_source_node.model = model - obj_source_node.created_at = datetime.now() - graphDb_data_Access = graphDBdataAccess(graph) - graphDb_data_Access.create_source_node(obj_source_node) - - local_file_result = extract_graph_from_file_local_file(graph, model, file_name, merged_file_path, '', '') - - print(local_file_result) - except AssertionError as e: - print('Failed due to file does not exist means not uploaded or accidentaly deleteled from server') - print("Failed: Error from extract function ", e) - -# Check for Wikipedia file to be test -def test_graph_from_Wikipedia(model_name): - model = model_name - wiki_query = 'https://en.wikipedia.org/wiki/Ram_Mandir' - source_type = 'Wikipedia' - file_name = "Ram_Mandir" - create_source_node_graph_url_wikipedia(graph, model, wiki_query, source_type) - wikiresult = extract_graph_from_file_Wikipedia(uri, userName, password, database, model, file_name, 1, 'en', '', '') - logging.info("Info: Wikipedia test done") - print(wikiresult) - + +# Initialize database connection +graph = create_graph_database_connection(URI, USERNAME, PASSWORD, DATABASE) + +def create_source_node_local(graph, model, file_name): + """Creates a source node for a local file.""" + source_node = sourceNode() + source_node.file_name = file_name + source_node.file_type = 'pdf' + source_node.file_size = '1087' + source_node.file_source = 'local file' + source_node.model = model + source_node.created_at = dt.now() + graphDB_data_Access = graphDBdataAccess(graph) + graphDB_data_Access.create_source_node(source_node) + return source_node + +def test_graph_from_file_local(model_name): + """Test graph creation from a local file.""" + file_name = 'About Amazon.pdf' + shutil.copyfile('/workspaces/llm-graph-builder/backend/files/About Amazon.pdf', + os.path.join(MERGED_DIR, file_name)) + + create_source_node_local(graph, model_name, file_name) + merged_file_path = os.path.join(MERGED_DIR, file_name) + + local_file_result = extract_graph_from_file_local_file( + URI, USERNAME, PASSWORD, DATABASE, model_name, merged_file_path, file_name, '', '' + ) + logging.info("Local file processing complete") + print(local_file_result) + try: - assert wikiresult['status'] == 'Completed' and wikiresult['nodeCount'] > 0 and wikiresult['relationshipCount'] > 0 - return wikiresult + assert local_file_result['status'] == 'Completed' + assert local_file_result['nodeCount'] > 0 + assert local_file_result['relationshipCount'] > 0 print("Success") except AssertionError as e: - print("Fail ", e) - return wikiresult - + print("Fail: ", e) -def test_graph_from_Wikipedia_failed(): - wiki_query = 'Test QA 123456' - source_type = 'Wikipedia' - try: - logging.info("Created source node for wikipedia") - create_source_node_graph_url_wikipedia(graph, model, wiki_query, source_type) - except AssertionError as e: - print("Fail ", e) + return local_file_result -# Check for Youtube_video to be Success -def test_graph_from_youtube_video(model_name): - model = model_name - source_url = 'https://www.youtube.com/watch?v=T-qy-zPWgqA' - source_type = 'youtube' +def test_graph_from_wikipedia(model_name): + """Test graph creation from a Wikipedia page.""" + wiki_query = 'https://en.wikipedia.org/wiki/Ram_Mandir' + source_type = 'Wikipedia' + file_name = "Ram_Mandir" + create_source_node_graph_url_wikipedia(graph, model_name, wiki_query, source_type) - create_source_node_graph_url_youtube(graph, model, source_url, source_type) - youtuberesult = extract_graph_from_file_youtube(uri, userName, password, database, model, source_url, '', '') + wiki_result = extract_graph_from_file_Wikipedia(URI, USERNAME, PASSWORD, DATABASE, model_name, file_name, 1, 'en', '', '') + logging.info("Wikipedia test done") + print(wiki_result) - logging.info("Info: Youtube Video test done") - print(youtuberesult) try: - assert youtuberesult['status'] == 'Completed' and youtuberesult['nodeCount'] > 1 and youtuberesult[ - 'relationshipCount'] > 1 - return youtuberesult + assert wiki_result['status'] == 'Completed' + assert wiki_result['nodeCount'] > 0 + assert wiki_result['relationshipCount'] > 0 print("Success") except AssertionError as e: - print("Failed ", e) - return youtuberesult - -# Check for Youtube_video to be Failed - -def test_graph_from_youtube_video_failed(): - url = 'https://www.youtube.com/watch?v=U9mJuUkhUzk' - source_type = 'youtube' - - create_source_node_graph_url_youtube(graph, model, url, source_type) - youtuberesult = extract_graph_from_file_youtube(graph, model, url, ',', ',') - # print(result) - print(youtuberesult) - try: - assert youtuberesult['status'] == 'Completed' - return youtuberesult - except AssertionError as e: - print("Failed ", e) - - -# Check for the GCS file to be uploaded, process and completed - -def test_graph_from_file_test_gcs(): - bucket_name = 'test' - folder_name = 'test' - source_type = 'gcs test bucket' - file_name = 'Neuralink brain chip patient playing chess.pdf' - create_source_node_graph_url_gcs(graph, model, bucket_name, folder_name, source_type) - gcsresult = extract_graph_from_file_gcs(graph, model, bucket_name, folder_name, file_name, '', '') - - logging.info("Info") - print(gcsresult) - - try: - assert gcsresult['status'] == 'Completed' and gcsresult['nodeCount'] > 10 and gcsresult['relationshipCount'] > 5 - print("Success") - except AssertionError as e: - print("Failed ", e) - - -def test_graph_from_file_test_gcs_failed(): - bucket_name = 'llm_graph_test' - folder_name = 'test' - source_type = 'gcs bucket' - # file_name = 'Neuralink brain chip patient playing chess.pdf' - try: - create_source_node_graph_url_gcs(graph, model, bucket_name, folder_name, source_type) - print("GCS: Create source node failed due to bucket not exist") - except AssertionError as e: - print("Failed ", e) - - -def test_graph_from_file_test_s3_failed(): - source_url = 's3://development-llm-test/' - try: - create_source_node_graph_url_s3(graph, model, source_url, 'test123', 'pwd123') - # assert result['status'] == 'Failed' - # print("S3 created source node failed die to wrong access key id and secret") - except AssertionError as e: - print("Failed ", e) - - -# Check the Functionality of Chatbot QnA for mode 'graph+vector' -def test_chatbot_QnA(model_name): - model = model_name - QA_n_RAG = QA_RAG(graph, model, 'Tell me about amazon', '[]', 1, 'graph+vector') + print("Fail: ", e) + + return wiki_result + +def test_graph_website(model_name): + """Test graph creation from a Website page.""" + #graph, model, source_url, source_type + source_url = 'https://www.amazon.com/' + source_type = 'web-url' + create_source_node_graph_web_url(graph, model_name, source_url, source_type) + + weburl_result = extract_graph_from_web_page(URI, USERNAME, PASSWORD, DATABASE, model_name, source_url, '', '') + logging.info("WebUrl test done") + print(weburl_result) - print(QA_n_RAG) - print(len(QA_n_RAG['message'])) try: - assert len(QA_n_RAG['message']) > 20 - return QA_n_RAG + assert weburl_result['status'] == 'Completed' + assert weburl_result['nodeCount'] > 0 + assert weburl_result['relationshipCount'] > 0 print("Success") except AssertionError as e: - print("Failed ", e) - return QA_n_RAG + print("Fail: ", e) + return weburl_result -# Check the Functionality of Chatbot QnA for mode 'vector' -def test_chatbot_QnA_vector(model_name): - model = model_name - QA_n_RAG_vector = QA_RAG(graph, model, 'Tell me about amazon', '[]', 1, 'vector') +def test_graph_from_youtube_video(model_name): + """Test graph creation from a YouTube video.""" + source_url = 'https://www.youtube.com/watch?v=T-qy-zPWgqA' + source_type = 'youtube' + create_source_node_graph_url_youtube(graph, model_name, source_url, source_type) + youtube_result = extract_graph_from_file_youtube( + URI, USERNAME, PASSWORD, DATABASE, model_name, source_url, '', '' + ) + logging.info("YouTube Video test done") + print(youtube_result) - print(QA_n_RAG_vector) - print(len(QA_n_RAG_vector['message'])) try: - assert len(QA_n_RAG_vector['message']) > 20 - return QA_n_RAG_vector + assert youtube_result['status'] == 'Completed' + assert youtube_result['nodeCount'] > 1 + assert youtube_result['relationshipCount'] > 1 print("Success") except AssertionError as e: - print("Failed ", e) - return QA_n_RAG_vector - -# Check the Functionality of Chatbot QnA for mode 'hybrid' + print("Failed: ", e) -def test_chatbot_QnA_hybrid(model_name): - model = model_name - QA_n_RAG_hybrid = QA_RAG(graph, model, 'Tell me about amazon', '[]', 1, 'hybrid') + return youtube_result +def test_chatbot_qna(model_name, mode='vector'): + """Test chatbot QnA functionality for different modes.""" + QA_n_RAG = QA_RAG(graph, model_name, 'Tell me about amazon', '[]', 1, mode) + print(QA_n_RAG) + print(len(QA_n_RAG['message'])) - print(QA_n_RAG_hybrid) - print(len(QA_n_RAG_hybrid['message'])) try: - assert len(QA_n_RAG_hybrid['message']) > 20 - return QA_n_RAG_hybrid + assert len(QA_n_RAG['message']) > 20 + return QA_n_RAG print("Success") except AssertionError as e: print("Failed ", e) - return QA_n_RAG_hybrid - - + return QA_n_RAG + +#Get Test disconnected_nodes list +def disconected_nodes(): + #graph = create_graph_database_connection(uri, userName, password, database) + graphDb_data_Access = graphDBdataAccess(graph) + nodes_list, total_nodes = graphDb_data_Access.list_unconnected_nodes() + print(nodes_list[0]["e"]["elementId"]) + status = "False" + + if total_nodes['total']>0: + status = "True" + else: + status = "False" + + return nodes_list[0]["e"]["elementId"], status + +#Test Delete delete_disconnected_nodes list +def delete_disconected_nodes(lst_element_id): + print(f'disconnect elementid list {lst_element_id}') + #graph = create_graph_database_connection(uri, userName, password, database) + graphDb_data_Access = graphDBdataAccess(graph) + result = graphDb_data_Access.delete_unconnected_nodes(json.dumps(lst_element_id)) + print(f'delete disconnect api result {result}') + if not result: + return "True" + else: + return "False" + +#Test Get Duplicate_nodes +def get_duplicate_nodes(): + #graph = create_graph_database_connection(uri, userName, password, database) + graphDb_data_Access = graphDBdataAccess(graph) + nodes_list, total_nodes = graphDb_data_Access.get_duplicate_nodes_list() + if total_nodes['total']>0: + return "True" + else: + return "False" + +#Test populate_graph_schema +def test_populate_graph_schema_from_text(model): + result_schema = populate_graph_schema_from_text('When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble.', model, True) + print(result_schema) + return result_schema + +# def compare_graph_results(results): +# """ +# Compare graph results across different models. +# Add custom logic here to compare graph data, nodes, and relationships. +# """ +# # Placeholder logic for comparison +# print("Comparing results...") +# for i in range(len(results) - 1): +# result_a = results[i] +# result_b = results[i + 1] +# if result_a == result_b: +# print(f"Result {i} is identical to result {i+1}") +# else: +# print(f"Result {i} differs from result {i+1}") + +def run_tests(): + final_list = [] + error_list = [] + models = ['openai-gpt-3.5', 'openai-gpt-4o'] + + for model_name in models: + try: + final_list.append(test_graph_from_file_local(model_name)) + final_list.append(test_graph_from_wikipedia(model_name)) + final_list.append(test_populate_graph_schema_from_text(model_name)) + final_list.append(test_graph_website(model_name)) + final_list.append(test_graph_from_youtube_video(model_name)) + final_list.append(test_chatbot_qna(model_name)) + final_list.append(test_chatbot_qna(model_name, mode='vector')) + final_list.append(test_chatbot_qna(model_name, mode='graph+vector+fulltext')) + except Exception as e: + error_list.append((model_name, str(e))) + # #Compare and log diffrences in graph results + # # compare_graph_results(final_list) # Pass the final_list to comapre_graph_results + # test_populate_graph_schema_from_text('openai-gpt-4o') + dis_elementid, dis_status = disconected_nodes() + lst_element_id = [dis_elementid] + delt = delete_disconected_nodes(lst_element_id) + dup = get_duplicate_nodes() + # schma = test_populate_graph_schema_from_text(model) + # Save final results to CSV + df = pd.DataFrame(final_list) + print(df) + df['execution_date'] = dt.today().strftime('%Y-%m-%d') + df['disconnected_nodes']=dis_status + df['get_duplicate_nodes']=dup + df['delete_disconected_nodes']=delt + # df['test_populate_graph_schema_from_text'] = schma + df.to_csv(f"Integration_TestResult_{dt.now().strftime('%Y%m%d_%H%M%S')}.csv", index=False) + + # Save error details to CSV + df_errors = pd.DataFrame(error_list, columns=['Model', 'Error']) + df_errors['execution_date'] = dt.today().strftime('%Y-%m-%d') + df_errors.to_csv(f"Error_details_{dt.now().strftime('%Y%m%d_%H%M%S')}.csv", index=False) if __name__ == "__main__": - final_list = [] - for model_name in ['openai-gpt-3.5','azure_ai_gpt_35','azure_ai_gpt_4o','anthropic_claude_3_5_sonnet','fireworks_llama_v3_70b','bedrock_claude_3_5_sonnet']: - - # local file - response = test_graph_from_file_local_file(model_name) - final_list.append(response) - - # # Wikipedia Test - response = test_graph_from_Wikipedia(model_name) - final_list.append(response) - - # # Youtube Test - response= test_graph_from_youtube_video(model_name) - final_list.append(response) - # # print(final_list) - - # # test_graph_from_file_test_gcs(model_name) # GCS Test - - # #chatbot 'graph+vector' - response = test_chatbot_QnA(model_name) - final_list.append(response) - - # #chatbot 'vector' - response = test_chatbot_QnA_vector(model_name) - final_list.append(response) - - # #chatbot 'hybrid' - response = test_chatbot_QnA_hybrid(model_name) - final_list.append(response) - - # test_graph_from_file_test_s3_failed() # S3 Failed Test Case - df = pd.DataFrame(final_list) - df['execution_date']= datetime.today().strftime('%Y-%m-%d') - df.to_csv(f"Integration_TestResult_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv", index=False) \ No newline at end of file + run_tests() \ No newline at end of file diff --git a/example.env b/example.env index b443fd18d..23bcc6e06 100644 --- a/example.env +++ b/example.env @@ -1,27 +1,27 @@ # Mandatory -OPENAI_API_KEY = "" -DIFFBOT_API_KEY = "" +OPENAI_API_KEY="" +DIFFBOT_API_KEY="" # Optional Backend -EMBEDDING_MODEL = "all-MiniLM-L6-v2" -IS_EMBEDDING = "true" -KNN_MIN_SCORE = "0.94" +EMBEDDING_MODEL="all-MiniLM-L6-v2" +IS_EMBEDDING="true" +KNN_MIN_SCORE="0.94" # Enable Gemini (default is False) | Can be False or True -GEMINI_ENABLED = False +GEMINI_ENABLED=False # LLM_MODEL_CONFIG_ollama_llama3="llama3,http://host.docker.internal:11434" # Enable Google Cloud logs (default is False) | Can be False or True -GCP_LOG_METRICS_ENABLED = False -NUMBER_OF_CHUNKS_TO_COMBINE = 6 -UPDATE_GRAPH_CHUNKS_PROCESSED = 20 -NEO4J_URI = "neo4j://database:7687" -NEO4J_USERNAME = "neo4j" -NEO4J_PASSWORD = "password" -LANGCHAIN_API_KEY = "" -LANGCHAIN_PROJECT = "" -LANGCHAIN_TRACING_V2 = "true" -LANGCHAIN_ENDPOINT = "https://api.smith.langchain.com" -GCS_FILE_CACHE = False +GCP_LOG_METRICS_ENABLED=False +NUMBER_OF_CHUNKS_TO_COMBINE=6 +UPDATE_GRAPH_CHUNKS_PROCESSED=20 +NEO4J_URI="neo4j://database:7687" +NEO4J_USERNAME="neo4j" +NEO4J_PASSWORD="password" +LANGCHAIN_API_KEY="" +LANGCHAIN_PROJECT="" +LANGCHAIN_TRACING_V2="true" +LANGCHAIN_ENDPOINT="https://api.smith.langchain.com" +GCS_FILE_CACHE=False ENTITY_EMBEDDING=True # Optional Frontend @@ -30,9 +30,8 @@ VITE_BLOOM_URL="https://workspace-preview.neo4j.io/workspace/explore?connectURL= VITE_REACT_APP_SOURCES="local,youtube,wiki,s3,web" VITE_LLM_MODELS="diffbot,openai-gpt-3.5,openai-gpt-4o" # ",ollama_llama3" VITE_ENV="DEV" -VITE_TIME_PER_CHUNK=4 VITE_TIME_PER_PAGE=50 VITE_CHUNK_SIZE=5242880 VITE_GOOGLE_CLIENT_ID="" VITE_CHAT_MODES="" -VITE_BATCH_SIZE=2 \ No newline at end of file +VITE_BATCH_SIZE=2 diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 7a31d5bcf..c3a7c1c82 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -6,7 +6,6 @@ ARG VITE_REACT_APP_SOURCES="" ARG VITE_LLM_MODELS="" ARG VITE_GOOGLE_CLIENT_ID="" ARG VITE_BLOOM_URL="https://workspace-preview.neo4j.io/workspace/explore?connectURL={CONNECT_URL}&search=Show+me+a+graph&featureGenAISuggestions=true&featureGenAISuggestionsInternal=true" -ARG VITE_TIME_PER_CHUNK=4 ARG VITE_TIME_PER_PAGE=50 ARG VITE_LARGE_FILE_SIZE=5242880 ARG VITE_CHUNK_SIZE=5242880 @@ -23,8 +22,8 @@ RUN VITE_BACKEND_API_URL=$VITE_BACKEND_API_URL \ VITE_LLM_MODELS=$VITE_LLM_MODELS \ VITE_GOOGLE_CLIENT_ID=$VITE_GOOGLE_CLIENT_ID \ VITE_BLOOM_URL=$VITE_BLOOM_URL \ - VITE_TIME_PER_CHUNK=$VITE_TIME_PER_CHUNK \ VITE_CHUNK_SIZE=$VITE_CHUNK_SIZE \ + VITE_TIME_PER_PAGE=$VITE_TIME_PER_PAGE \ VITE_ENV=$VITE_ENV \ VITE_LARGE_FILE_SIZE=${VITE_LARGE_FILE_SIZE} \ VITE_CHAT_MODES=$VITE_CHAT_MODES \ diff --git a/frontend/example.env b/frontend/example.env index 05b8cdf60..63bd3e7c3 100644 --- a/frontend/example.env +++ b/frontend/example.env @@ -3,7 +3,6 @@ VITE_BLOOM_URL="https://workspace-preview.neo4j.io/workspace/explore?connectURL= VITE_REACT_APP_SOURCES="local,youtube,wiki,s3,web" VITE_LLM_MODELS="diffbot,openai-gpt-3.5,openai-gpt-4o" VITE_ENV="DEV" -VITE_TIME_PER_CHUNK=4 VITE_TIME_PER_PAGE=50 VITE_CHUNK_SIZE=5242880 VITE_LARGE_FILE_SIZE=5242880 diff --git a/frontend/src/API/Index.ts b/frontend/src/API/Index.ts new file mode 100644 index 000000000..f4ad15cbe --- /dev/null +++ b/frontend/src/API/Index.ts @@ -0,0 +1,7 @@ +import axios from 'axios'; +import { url } from '../utils/Utils'; + +const api = axios.create({ + baseURL: url(), +}); +export default api; diff --git a/frontend/src/App.css b/frontend/src/App.css index ff084ffae..fe285c972 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -233,10 +233,8 @@ letter-spacing: 0; line-height: 1.25rem; width: max-content; - height: 30px; text-overflow: ellipsis; white-space: nowrap; - overflow: hidden; } .ndl-widget-content>div { @@ -365,4 +363,13 @@ .widthunset{ width: initial !important; height: initial !important; +} + +.text-input-container { + transition: width 1.5s ease; + /* width: 100dvh; */ +} + +.text-input-container.search-initiated { + width: 60dvh; } \ No newline at end of file diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index 7bd837299..89c15ea72 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -18,13 +18,20 @@ import wikipedialogo from '../../assets/images/wikipedia.svg'; import youtubelogo from '../../assets/images/youtube.svg'; import gcslogo from '../../assets/images/gcs.webp'; import s3logo from '../../assets/images/s3logo.png'; -import { Chunk, Entity, ExtendedNode, GroupedEntity, UserCredentials, chatInfoMessage } from '../../types'; +import { + Chunk, + Entity, + ExtendedNode, + ExtendedRelationship, + GroupedEntity, + UserCredentials, + chatInfoMessage, +} from '../../types'; import { useContext, useEffect, useMemo, useState } from 'react'; import HoverableLink from '../UI/HoverableLink'; import GraphViewButton from '../Graph/GraphViewButton'; import { chunkEntitiesAPI } from '../../services/ChunkEntitiesInfo'; import { useCredentials } from '../../context/UserCredentials'; -import type { Relationship } from '@neo4j-nvl/base'; import { calcWordColor } from '@neo4j-devtools/word-color'; import ReactMarkdown from 'react-markdown'; import { GlobeAltIconOutline } from '@neo4j-ndl/react/icons'; @@ -51,7 +58,7 @@ const ChatInfoModal: React.FC = ({ const [loading, setLoading] = useState(false); const { userCredentials } = useCredentials(); const [nodes, setNodes] = useState([]); - const [relationships, setRelationships] = useState([]); + const [relationships, setRelationships] = useState([]); const [chunks, setChunks] = useState([]); const themeUtils = useContext(ThemeWrapperContext); const [, copy] = useCopyToClipboard(); @@ -168,7 +175,11 @@ const ChatInfoModal: React.FC = ({ ) : ( {mode != 'graph' ? Sources used : <>} - {mode === 'graph+vector' || mode === 'graph' ? Top Entities used : <>} + {mode === 'graph+vector' || mode === 'graph' || mode === 'graph+vector+fulltext' ? ( + Top Entities used + ) : ( + <> + )} {mode === 'graph' && cypher_query?.trim().length ? ( Generated Cypher Query ) : ( diff --git a/frontend/src/components/ChatBot/ChatModeToggle.tsx b/frontend/src/components/ChatBot/ChatModeToggle.tsx index 4c0d54bc7..e82dfea4d 100644 --- a/frontend/src/components/ChatBot/ChatModeToggle.tsx +++ b/frontend/src/components/ChatBot/ChatModeToggle.tsx @@ -31,7 +31,12 @@ export default function ChatModeToggle({ () => chatModes?.map((m) => { return { - title: capitalize(m), + title: m.includes('+') + ? m + .split('+') + .map((s) => capitalize(s)) + .join('+') + : capitalize(m), onClick: () => { setchatMode(m); }, diff --git a/frontend/src/components/ChatBot/Info/InfoModal.tsx b/frontend/src/components/ChatBot/Info/InfoModal.tsx index 0dd325731..cf1bbca47 100644 --- a/frontend/src/components/ChatBot/Info/InfoModal.tsx +++ b/frontend/src/components/ChatBot/Info/InfoModal.tsx @@ -6,13 +6,20 @@ import wikipedialogo from '../../../assets/images/Wikipedia-logo-v2.svg'; import youtubelogo from '../../../assets/images/youtube.png'; import gcslogo from '../../../assets/images/gcs.webp'; import s3logo from '../../../assets/images/s3logo.png'; -import { Chunk, Entity, ExtendedNode, GroupedEntity, UserCredentials, chatInfoMessage } from '../../../types'; +import { + Chunk, + Entity, + ExtendedNode, + ExtendedRelationship, + GroupedEntity, + UserCredentials, + chatInfoMessage, +} from '../../../types'; import { useEffect, useMemo, useState } from 'react'; import HoverableLink from '../../UI/HoverableLink'; import GraphViewButton from '../../Graph/GraphViewButton'; import { chunkEntitiesAPI } from '../../../services/ChunkEntitiesInfo'; import { useCredentials } from '../../../context/UserCredentials'; -import type { Relationship } from '@neo4j-nvl/base'; import { calcWordColor } from '@neo4j-devtools/word-color'; import ReactMarkdown from 'react-markdown'; import { GlobeAltIconOutline } from '@neo4j-ndl/react/icons'; @@ -23,7 +30,7 @@ const InfoModal: React.FC = ({ sources, model, total_tokens, re const [loading, setLoading] = useState(false); const { userCredentials } = useCredentials(); const [nodes, setNodes] = useState([]); - const [relationships, setRelationships] = useState([]); + const [relationships, setRelationships] = useState([]); const [chunks, setChunks] = useState([]); const parseEntity = (entity: Entity) => { const { labels, properties } = entity; diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index ec4fad9bb..4bde5a9b4 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -31,6 +31,8 @@ import FallBackDialog from './UI/FallBackDialog'; import DeletePopUp from './Popups/DeletePopUp/DeletePopUp'; import GraphEnhancementDialog from './Popups/GraphEnhancementDialog'; import { tokens } from '@neo4j-ndl/base'; +import axios from 'axios'; + const ConnectionModal = lazy(() => import('./Popups/ConnectionModal/ConnectionModal')); const ConfirmationDialog = lazy(() => import('./Popups/LargeFilePopUp/ConfirmationDialog')); let afterFirstRender = false; @@ -180,6 +182,7 @@ const Content: React.FC = ({ }; const extractHandler = async (fileItem: CustomFile, uid: string) => { + queue.remove(fileItem.name as string); try { setFilesData((prevfiles) => prevfiles.map((curfile) => { @@ -252,28 +255,45 @@ const Content: React.FC = ({ }); } } catch (err: any) { - const error = JSON.parse(err.message); - if (Object.keys(error).includes('fileName')) { - const { message } = error; - const { fileName } = error; - const errorMessage = error.message; - setalertDetails({ - showAlert: true, - alertType: 'error', - alertMessage: message, - }); - setFilesData((prevfiles) => - prevfiles.map((curfile) => { - if (curfile.name == fileName) { - return { - ...curfile, - status: 'Failed', - errorMessage, - }; - } - return curfile; - }) - ); + if (err instanceof Error) { + try { + const error = JSON.parse(err.message); + if (Object.keys(error).includes('fileName')) { + setProcessedCount((prev) => { + if (prev == batchSize) { + return batchSize - 1; + } + return prev + 1; + }); + const { message, fileName } = error; + queue.remove(fileName); + const errorMessage = error.message; + setalertDetails({ + showAlert: true, + alertType: 'error', + alertMessage: message, + }); + setFilesData((prevfiles) => + prevfiles.map((curfile) => { + if (curfile.name == fileName) { + return { ...curfile, status: 'Failed', errorMessage }; + } + return curfile; + }) + ); + } else { + console.error('Unexpected error format:', error); + } + } catch (parseError) { + if (axios.isAxiosError(err)) { + const axiosErrorMessage = err.response?.data?.message || err.message; + console.error('Axios error occurred:', axiosErrorMessage); + } else { + console.error('An unexpected error occurred:', err.message); + } + } + } else { + console.error('An unknown error occurred:', err); } } }; @@ -302,7 +322,10 @@ const Content: React.FC = ({ return data; }; - const addFilesToQueue = (remainingFiles: CustomFile[]) => { + const addFilesToQueue = async (remainingFiles: CustomFile[]) => { + if (!remainingFiles.length) { + await postProcessing(userCredentials as UserCredentials, postProcessingTasks); + } remainingFiles.forEach((f) => { setFilesData((prev) => prev.map((pf) => { @@ -379,13 +402,11 @@ const Content: React.FC = ({ } Promise.allSettled(data).then(async (_) => { setextractLoading(false); - await postProcessing(userCredentials as UserCredentials, postProcessingTasks); }); - } else if (queueFiles && !queue.isEmpty()) { + } else if (queueFiles && !queue.isEmpty() && processingFilesCount < batchSize) { data = scheduleBatchWiseProcess(queue.items, true); Promise.allSettled(data).then(async (_) => { setextractLoading(false); - await postProcessing(userCredentials as UserCredentials, postProcessingTasks); }); } else { addFilesToQueue(filesTobeProcessed as CustomFile[]); @@ -405,7 +426,6 @@ const Content: React.FC = ({ } Promise.allSettled(data).then(async (_) => { setextractLoading(false); - await postProcessing(userCredentials as UserCredentials, postProcessingTasks); }); } else { const selectedNewFiles = childRef.current?.getSelectedRows().filter((f) => f.status === 'New'); diff --git a/frontend/src/components/Dropdown.tsx b/frontend/src/components/Dropdown.tsx index f046bb8ff..ba949aec0 100644 --- a/frontend/src/components/Dropdown.tsx +++ b/frontend/src/components/Dropdown.tsx @@ -1,6 +1,6 @@ import { Dropdown, Tip } from '@neo4j-ndl/react'; import { OptionType, ReusableDropdownProps } from '../types'; -import { useMemo } from 'react'; +import { useMemo, useReducer } from 'react'; import { capitalize } from '../utils/Utils'; const DropdownComponent: React.FC = ({ @@ -13,6 +13,7 @@ const DropdownComponent: React.FC = ({ isDisabled, value, }) => { + const [disableTooltip, toggleDisableState] = useReducer((state) => !state, false); const handleChange = (selectedOption: OptionType | null | void) => { onSelect(selectedOption); }; @@ -20,7 +21,7 @@ const DropdownComponent: React.FC = ({ return ( <>
- + = ({ menuPlacement: 'auto', isDisabled: isDisabled, value: value, + onMenuOpen: () => { + toggleDisableState(); + }, + onMenuClose: () => { + toggleDisableState(); + }, }} size='medium' fluid diff --git a/frontend/src/components/FileTable.tsx b/frontend/src/components/FileTable.tsx index 70dff8f1a..23310eaf4 100644 --- a/frontend/src/components/FileTable.tsx +++ b/frontend/src/components/FileTable.tsx @@ -761,6 +761,13 @@ const FileTable = forwardRef((props, ref) => { return curfile; }) ); + setProcessedCount((prev) => { + if (prev == batchSize) { + return batchSize - 1; + } + return prev + 1; + }); + queue.remove(fileName); } else { let errorobj = { error: res.data.error, message: res.data.message, fileName }; throw new Error(JSON.stringify(errorobj)); diff --git a/frontend/src/components/Graph/GraphViewModal.tsx b/frontend/src/components/Graph/GraphViewModal.tsx index 9c0d5d190..39438b788 100644 --- a/frontend/src/components/Graph/GraphViewModal.tsx +++ b/frontend/src/components/Graph/GraphViewModal.tsx @@ -1,6 +1,23 @@ -import { Banner, Dialog, Flex, IconButtonArray, LoadingSpinner, Typography } from '@neo4j-ndl/react'; +import { + Banner, + Dialog, + Flex, + IconButton, + IconButtonArray, + LoadingSpinner, + TextInput, + Typography, + useDebounce, +} from '@neo4j-ndl/react'; import { useCallback, useEffect, useRef, useState } from 'react'; -import { ExtendedNode, GraphType, GraphViewModalProps, Scheme, UserCredentials } from '../../types'; +import { + ExtendedNode, + ExtendedRelationship, + GraphType, + GraphViewModalProps, + Scheme, + UserCredentials, +} from '../../types'; import { InteractiveNvlWrapper } from '@neo4j-nvl/react'; import NVL from '@neo4j-nvl/base'; import type { Node, Relationship } from '@neo4j-nvl/base'; @@ -9,16 +26,26 @@ import { ArrowPathIconOutline, DragIcon, FitToScreenIcon, + MagnifyingGlassIconOutline, MagnifyingGlassMinusIconOutline, MagnifyingGlassPlusIconOutline, } from '@neo4j-ndl/react/icons'; import IconButtonWithToolTip from '../UI/IconButtonToolTip'; -import { filterData, processGraphData } from '../../utils/Utils'; +import { filterData, processGraphData, sortAlphabetically } from '../../utils/Utils'; import { useCredentials } from '../../context/UserCredentials'; import { LegendsChip } from './LegendsChip'; import graphQueryAPI from '../../services/GraphQuery'; -import { graphLabels, intitalGraphType, mouseEventCallbacks, nvlOptions, queryMap } from '../../utils/Constants'; +import { + graphLabels, + intitalGraphType, + mouseEventCallbacks, + nvlOptions, + queryMap, + RESULT_STEP_SIZE, +} from '../../utils/Constants'; import CheckboxSelection from './CheckboxSelection'; +import { ShowAll } from '../UI/ShowAll'; + const GraphViewModal: React.FunctionComponent = ({ open, inspectedName, @@ -40,6 +67,10 @@ const GraphViewModal: React.FunctionComponent = ({ const { userCredentials } = useCredentials(); const [scheme, setScheme] = useState({}); const [newScheme, setNewScheme] = useState({}); + const [searchQuery, setSearchQuery] = useState(''); + const debouncedQuery = useDebounce(searchQuery, 300); + + // the checkbox selection const handleCheckboxChange = (graph: GraphType) => { const currentIndex = graphType.indexOf(graph); const newGraphSelected = [...graphType]; @@ -50,9 +81,18 @@ const GraphViewModal: React.FunctionComponent = ({ newGraphSelected.splice(currentIndex, 1); initGraph(newGraphSelected, allNodes, allRelationships, scheme); } + setSearchQuery(''); setGraphType(newGraphSelected); }; + const nodeCount = (nodes: ExtendedNode[], label: string): number => { + return [...new Set(nodes?.filter((n) => n.labels?.includes(label)).map((i) => i.id))].length; + }; + + const relationshipCount = (relationships: ExtendedRelationship[], label: string): number => { + return [...new Set(relationships?.filter((r) => r.caption?.includes(label)).map((i) => i.id))].length; + }; + const graphQuery: string = graphType.includes('DocumentChunk') && graphType.includes('Entities') ? queryMap.DocChunkEntities @@ -62,6 +102,7 @@ const GraphViewModal: React.FunctionComponent = ({ ? queryMap.Entities : ''; + // fit graph to original position const handleZoomToFit = () => { nvlRef.current?.fit( allNodes.map((node) => node.id), @@ -75,7 +116,9 @@ const GraphViewModal: React.FunctionComponent = ({ handleZoomToFit(); }, 10); return () => { - nvlRef.current?.destroy(); + if (nvlRef.current) { + nvlRef.current?.destroy(); + } setGraphType(intitalGraphType); clearTimeout(timeoutId); setScheme({}); @@ -83,6 +126,7 @@ const GraphViewModal: React.FunctionComponent = ({ setRelationships([]); setAllNodes([]); setAllRelationships([]); + setSearchQuery(''); }; }, []); @@ -151,6 +195,71 @@ const GraphViewModal: React.FunctionComponent = ({ } }, [open]); + // The search and update nodes + const handleSearch = useCallback( + (value: string) => { + const query = value.toLowerCase(); + const updatedNodes = nodes.map((node) => { + if (query === '') { + return { + ...node, + activated: false, + selected: false, + size: graphLabels.nodeSize, + }; + } + const { id, properties, caption } = node; + const propertiesMatch = properties?.id?.toLowerCase().includes(query); + const match = id.toLowerCase().includes(query) || propertiesMatch || caption?.toLowerCase().includes(query); + return { + ...node, + activated: match, + selected: match, + size: + match && viewPoint === graphLabels.showGraphView + ? 100 + : match && viewPoint !== graphLabels.showGraphView + ? 50 + : graphLabels.nodeSize, + }; + }); + // deactivating any active relationships + const updatedRelationships = relationships.map((rel) => { + return { + ...rel, + activated: false, + selected: false, + }; + }); + setNodes(updatedNodes); + setRelationships(updatedRelationships); + }, + [nodes] + ); + + useEffect(() => { + handleSearch(debouncedQuery); + }, [debouncedQuery]); + + const initGraph = ( + graphType: GraphType[], + finalNodes: ExtendedNode[], + finalRels: Relationship[], + schemeVal: Scheme + ) => { + if (allNodes.length > 0 && allRelationships.length > 0) { + const { filteredNodes, filteredRelations, filteredScheme } = filterData( + graphType, + finalNodes ?? [], + finalRels ?? [], + schemeVal + ); + setNodes(filteredNodes); + setRelationships(filteredRelations); + setNewScheme(filteredScheme); + } + }; + // Unmounting the component if (!open) { return <>; @@ -201,10 +310,11 @@ const GraphViewModal: React.FunctionComponent = ({ setRelationships([]); setAllNodes([]); setAllRelationships([]); + setSearchQuery(''); }; // sort the legends in with Chunk and Document always the first two values - const legendCheck = Object.keys(newScheme).sort((a, b) => { + const nodeCheck = Object.keys(newScheme).sort((a, b) => { if (a === graphLabels.document || a === graphLabels.chunk) { return -1; } else if (b === graphLabels.document || b === graphLabels.chunk) { @@ -213,23 +323,75 @@ const GraphViewModal: React.FunctionComponent = ({ return a.localeCompare(b); }); - const initGraph = ( - graphType: GraphType[], - finalNodes: ExtendedNode[], - finalRels: Relationship[], - schemeVal: Scheme - ) => { - if (allNodes.length > 0 && allRelationships.length > 0) { - const { filteredNodes, filteredRelations, filteredScheme } = filterData( - graphType, - finalNodes ?? [], - finalRels ?? [], - schemeVal - ); - setNodes(filteredNodes); - setRelationships(filteredRelations); - setNewScheme(filteredScheme); + // get sorted relationships + const relationshipsSorted = relationships.sort(sortAlphabetically); + + // To get the relationship count + const groupedAndSortedRelationships: ExtendedRelationship[] = Object.values( + relationshipsSorted.reduce((acc: { [key: string]: ExtendedRelationship }, relType: Relationship) => { + const key = relType.caption || ''; + if (!acc[key]) { + acc[key] = { ...relType, count: 0 }; + } + + acc[key]!.count += relationshipCount(relationships as ExtendedRelationship[], key); + return acc; + }, {}) + ); + + // On Node Click, highlighting the nodes and deactivating any active relationships + const handleNodeClick = (nodeLabel: string) => { + const updatedNodes = nodes.map((node) => { + const isActive = node.labels.includes(nodeLabel); + return { + ...node, + activated: isActive, + selected: isActive, + size: + isActive && viewPoint === graphLabels.showGraphView + ? 100 + : isActive && viewPoint !== graphLabels.showGraphView + ? 50 + : graphLabels.nodeSize, + }; + }); + // deactivating any active relationships + const updatedRelationships = relationships.map((rel) => { + return { + ...rel, + activated: false, + selected: false, + }; + }); + if (searchQuery !== '') { + setSearchQuery(''); } + setNodes(updatedNodes); + setRelationships(updatedRelationships); + }; + // On Relationship Legend Click, highlight the relationships and deactivating any active nodes + const handleRelationshipClick = (nodeLabel: string) => { + const updatedRelations = relationships.map((rel) => { + return { + ...rel, + activated: rel?.caption?.includes(nodeLabel), + selected: rel?.caption?.includes(nodeLabel), + }; + }); + // // deactivating any active nodes + const updatedNodes = nodes.map((node) => { + return { + ...node, + activated: false, + selected: false, + size: graphLabels.nodeSize, + }; + }); + if (searchQuery !== '') { + setSearchQuery(''); + } + setRelationships(updatedRelations); + setNodes(updatedNodes); }; return ( @@ -334,17 +496,79 @@ const GraphViewModal: React.FunctionComponent = ({ handleClasses={{ left: 'ml-1' }} >
- - {graphLabels.resultOverview} - - {graphLabels.totalNodes} ({nodes.length}) - - -
- {legendCheck.map((key, index) => ( - - ))} -
+ {nodeCheck.length > 0 && ( + <> + + {graphLabels.resultOverview} +
+ { + setSearchQuery(e.target.value); + }} + placeholder='Search On Node Properties' + fluid={true} + leftIcon={ + + + + } + /> +
+ + {graphLabels.totalNodes} ({nodes.length}) + +
+
+ + {nodeCheck.map((nodeLabel, index) => ( + handleNodeClick(nodeLabel)} + /> + ))} + +
+ + )} + {relationshipsSorted.length > 0 && ( + <> + + + {graphLabels.totalRelationships} ({relationships.length}) + + +
+ + {groupedAndSortedRelationships.map((relType, index) => ( + handleRelationshipClick(relType.caption || '')} + /> + ))} + +
+ + )}
diff --git a/frontend/src/components/Graph/LegendsChip.tsx b/frontend/src/components/Graph/LegendsChip.tsx index 7e121dc67..2ab9c7b40 100644 --- a/frontend/src/components/Graph/LegendsChip.tsx +++ b/frontend/src/components/Graph/LegendsChip.tsx @@ -1,12 +1,6 @@ -import { useMemo } from 'react'; import { LegendChipProps } from '../../types'; import Legend from '../UI/Legend'; -export const LegendsChip: React.FunctionComponent = ({ scheme, title, nodes }) => { - const chunkcount = useMemo( - () => [...new Set(nodes?.filter((n) => n?.labels?.includes(title)).map((i) => i.id))].length, - [nodes] - ); - - return ; +export const LegendsChip: React.FunctionComponent = ({ scheme, label, type, count, onClick }) => { + return ; }; diff --git a/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx b/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx index 63e2d7883..ab9fe2399 100644 --- a/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx +++ b/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx @@ -60,41 +60,43 @@ export default function ConnectionModal({ }, [open]); const recreateVectorIndex = useCallback( - async (isNewVectorIndex: boolean) => { - try { - setVectorIndexLoading(true); - const response = await createVectorIndex(userCredentials as UserCredentials, isNewVectorIndex); - setVectorIndexLoading(false); - if (response.data.status === 'Failed') { - throw new Error(response.data.error); - } else { - setMessage({ - type: 'success', - content: 'Successfully created the vector index', - }); - setConnectionStatus(true); - localStorage.setItem( - 'neo4j.connection', - JSON.stringify({ - uri: userCredentials?.uri, - user: userCredentials?.userName, - password: userCredentials?.password, - database: userCredentials?.database, - userDbVectorIndex: 384, - }) - ); - } - } catch (error) { - setVectorIndexLoading(false); - if (error instanceof Error) { - console.log('Error in recreating the vector index', error.message); - setMessage({ type: 'danger', content: error.message }); + async (isNewVectorIndex: boolean, usercredential: UserCredentials) => { + if (usercredential != null && Object.values(usercredential).length) { + try { + setVectorIndexLoading(true); + const response = await createVectorIndex(usercredential as UserCredentials, isNewVectorIndex); + setVectorIndexLoading(false); + if (response.data.status === 'Failed') { + throw new Error(response.data.error); + } else { + setMessage({ + type: 'success', + content: 'Successfully created the vector index', + }); + setConnectionStatus(true); + localStorage.setItem( + 'neo4j.connection', + JSON.stringify({ + uri: usercredential?.uri, + user: usercredential?.userName, + password: usercredential?.password, + database: usercredential?.database, + userDbVectorIndex: 384, + }) + ); + } + } catch (error) { + setVectorIndexLoading(false); + if (error instanceof Error) { + console.log('Error in recreating the vector index', error.message); + setMessage({ type: 'danger', content: error.message }); + } } + setTimeout(() => { + setMessage({ type: 'unknown', content: '' }); + setOpenConnection((prev) => ({ ...prev, openPopUp: false })); + }, 3000); } - setTimeout(() => { - setMessage({ type: 'unknown', content: '' }); - setOpenConnection((prev) => ({ ...prev, openPopUp: false })); - }, 3000); }, [userCredentials, userDbVectorIndex] ); @@ -104,8 +106,9 @@ export default function ConnectionModal({ type: 'danger', content: ( recreateVectorIndex(chunksExistsWithDifferentEmbedding)} + recreateVectorIndex={() => + recreateVectorIndex(chunksExistsWithDifferentEmbedding, userCredentials as UserCredentials) + } isVectorIndexAlreadyExists={chunksExistsWithDifferentEmbedding || isVectorIndexMatch} userVectorIndexDimension={JSON.parse(localStorage.getItem('neo4j.connection') ?? 'null').userDbVectorIndex} chunksExists={chunksExistsWithoutEmbedding} @@ -113,7 +116,7 @@ export default function ConnectionModal({ ), }); } - }, [isVectorIndexMatch, vectorIndexLoading, chunksExistsWithDifferentEmbedding, chunksExistsWithoutEmbedding]); + }, [isVectorIndexMatch, chunksExistsWithDifferentEmbedding, chunksExistsWithoutEmbedding, userCredentials]); const parseAndSetURI = (uri: string, urlparams = false) => { const uriParts: string[] = uri.split('://'); @@ -189,7 +192,8 @@ export default function ConnectionModal({ const submitConnection = async () => { const connectionURI = `${protocol}://${URI}${URI.split(':')[1] ? '' : `:${port}`}`; - setUserCredentials({ uri: connectionURI, userName: username, password: password, database: database, port: port }); + const credential = { uri: connectionURI, userName: username, password: password, database: database, port: port }; + setUserCredentials(credential); setIsLoading(true); try { const response = await connectAPI(connectionURI, username, password, database); @@ -197,6 +201,16 @@ export default function ConnectionModal({ if (response?.data?.status !== 'Success') { throw new Error(response.data.error); } else { + localStorage.setItem( + 'neo4j.connection', + JSON.stringify({ + uri: connectionURI, + user: username, + password: password, + database: database, + userDbVectorIndex, + }) + ); setUserDbVectorIndex(response.data.data.db_vector_dimension); if ( (response.data.data.application_dimension === response.data.data.db_vector_dimension || @@ -214,27 +228,19 @@ export default function ConnectionModal({ type: 'danger', content: ( - recreateVectorIndex( - !( - response.data.data.db_vector_dimension > 0 && - response.data.data.db_vector_dimension != response.data.data.application_dimension - ) - ) - } + recreateVectorIndex={() => recreateVectorIndex(false, credential)} isVectorIndexAlreadyExists={response.data.data.db_vector_dimension != 0} chunksExists={true} /> ), }); + return; } else { setMessage({ type: 'danger', content: ( recreateVectorIndex(true)} + recreateVectorIndex={() => recreateVectorIndex(true, credential)} isVectorIndexAlreadyExists={ response.data.data.db_vector_dimension != 0 && response.data.data.db_vector_dimension != response.data.data.application_dimension @@ -244,17 +250,8 @@ export default function ConnectionModal({ /> ), }); + return; } - localStorage.setItem( - 'neo4j.connection', - JSON.stringify({ - uri: connectionURI, - user: username, - password: password, - database: database, - userDbVectorIndex, - }) - ); } } catch (error) { setIsLoading(false); @@ -266,6 +263,9 @@ export default function ConnectionModal({ } } setTimeout(() => { + if (connectionMessage?.type != 'danger') { + setMessage({ type: 'unknown', content: '' }); + } setPassword(''); }, 3000); }; diff --git a/frontend/src/components/Popups/ConnectionModal/VectorIndexMisMatchAlert.tsx b/frontend/src/components/Popups/ConnectionModal/VectorIndexMisMatchAlert.tsx index f9e85b63e..3c2965f44 100644 --- a/frontend/src/components/Popups/ConnectionModal/VectorIndexMisMatchAlert.tsx +++ b/frontend/src/components/Popups/ConnectionModal/VectorIndexMisMatchAlert.tsx @@ -2,21 +2,22 @@ import { Box, Flex } from '@neo4j-ndl/react'; import Markdown from 'react-markdown'; import ButtonWithToolTip from '../../UI/ButtonWithToolTip'; import { useCredentials } from '../../../context/UserCredentials'; +import { useState } from 'react'; export default function VectorIndexMisMatchAlert({ - vectorIndexLoading, recreateVectorIndex, isVectorIndexAlreadyExists, userVectorIndexDimension, chunksExists, }: { - vectorIndexLoading: boolean; recreateVectorIndex: () => Promise; isVectorIndexAlreadyExists: boolean; userVectorIndexDimension?: number; chunksExists: boolean; }) { const { userCredentials } = useCredentials(); + const [vectorIndexLoading, setVectorIndexLoading] = useState(false); + return ( @@ -42,7 +43,11 @@ To proceed, please choose one of the following options: label='creates the supported vector index' placement='top' loading={vectorIndexLoading} - onClick={() => recreateVectorIndex()} + onClick={async () => { + setVectorIndexLoading(true); + await recreateVectorIndex(); + setVectorIndexLoading(false); + }} className='!w-full' color='danger' disabled={userCredentials === null} diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx index bf8345550..f5a021e30 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx @@ -160,7 +160,7 @@ export default function DeduplicationTab() { return ( {info.getValue().map((l, index) => ( - + ))} ); diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx index 2dc8a13ff..373007e95 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx @@ -111,7 +111,7 @@ export default function DeletePopUpForOrphanNodes({ return ( {info.getValue().map((l, index) => ( - + ))} ); diff --git a/frontend/src/components/QuickStarter.tsx b/frontend/src/components/QuickStarter.tsx index 29832fee1..db2cba7e7 100644 --- a/frontend/src/components/QuickStarter.tsx +++ b/frontend/src/components/QuickStarter.tsx @@ -42,4 +42,4 @@ const QuickStarter: React.FunctionComponent = () => { ); }; -export default QuickStarter; \ No newline at end of file +export default QuickStarter; diff --git a/frontend/src/components/UI/Legend.tsx b/frontend/src/components/UI/Legend.tsx index d798ff4f4..a3c806669 100644 --- a/frontend/src/components/UI/Legend.tsx +++ b/frontend/src/components/UI/Legend.tsx @@ -3,16 +3,20 @@ import { GraphLabel } from '@neo4j-ndl/react'; export default function Legend({ bgColor, title, - chunkCount, + count, + type, + onClick, }: { bgColor: string; title: string; - chunkCount?: number; + count?: number; + type: 'node' | 'relationship' | 'propertyKey'; + tabIndex?: number; + onClick?: (e: React.MouseEvent) => void; }) { return ( - - {title} - {chunkCount && `(${chunkCount})`} + + {title} {count !== undefined && `(${count})`} ); } diff --git a/frontend/src/components/UI/ShowAll.tsx b/frontend/src/components/UI/ShowAll.tsx new file mode 100644 index 000000000..726146723 --- /dev/null +++ b/frontend/src/components/UI/ShowAll.tsx @@ -0,0 +1,38 @@ +import { Button } from '@neo4j-ndl/react'; +import type { ReactNode } from 'react'; +import { useState } from 'react'; + +// import { ButtonGroup } from '../button-group/button-group'; + +type ShowAllProps = { + initiallyShown: number; + /* pass thunk to enable rendering only shown components */ + children: ((() => ReactNode) | ReactNode)[]; + ariaLabel?: string; +}; +const isThunkComponent = (t: (() => ReactNode) | ReactNode): t is () => ReactNode => typeof t === 'function'; + +export function ShowAll({ initiallyShown, children }: ShowAllProps) { + const [expanded, setExpanded] = useState(false); + const toggleExpanded = () => setExpanded((e) => !e); + const itemCount = children.length; + const controlsNeeded = itemCount > initiallyShown; + const shown = expanded ? itemCount : initiallyShown; + const leftToShow = itemCount - shown; + + if (itemCount === 0) { + return null; + } + + const currentChildren = children.slice(0, shown).map((c) => (isThunkComponent(c) ? c() : c)); + return ( + <> +
{currentChildren}
+ {controlsNeeded && ( + + )} + + ); +} diff --git a/frontend/src/context/UsersFiles.tsx b/frontend/src/context/UsersFiles.tsx index 75f965d0a..fd3531403 100644 --- a/frontend/src/context/UsersFiles.tsx +++ b/frontend/src/context/UsersFiles.tsx @@ -58,7 +58,7 @@ const FileContextProvider: FC = ({ children }) => { const [selectedSchemas, setSelectedSchemas] = useState([]); const [rowSelection, setRowSelection] = useState>({}); const [selectedRows, setSelectedRows] = useState([]); - const [chatMode, setchatMode] = useState('graph+vector'); + const [chatMode, setchatMode] = useState('graph+vector+fulltext'); const [isSchema, setIsSchema] = useState(false); const [showTextFromSchemaDialog, setShowTextFromSchemaDialog] = useState({ triggeredFrom: '', diff --git a/frontend/src/hooks/useSse.tsx b/frontend/src/hooks/useSse.tsx index f8a07f61e..8b063751c 100644 --- a/frontend/src/hooks/useSse.tsx +++ b/frontend/src/hooks/useSse.tsx @@ -7,7 +7,7 @@ export default function useServerSideEvent( alertHandler: (inMinutes: boolean, minutes: number, filename: string) => void, errorHandler: (filename: string) => void ) { - const { setFilesData, setProcessedCount, queue } = useFileContext(); + const { setFilesData, setProcessedCount } = useFileContext(); function updateStatusForLargeFiles(eventSourceRes: eventResponsetypes) { const { fileName, @@ -45,7 +45,7 @@ export default function useServerSideEvent( }); }); } - } else if (status === 'Completed' || status === 'Cancelled') { + } else if (status === 'Completed') { setFilesData((prevfiles) => { return prevfiles.map((curfile) => { if (curfile.name == fileName) { @@ -67,7 +67,6 @@ export default function useServerSideEvent( } return prev + 1; }); - queue.remove(fileName); } else if (eventSourceRes.status === 'Failed') { setFilesData((prevfiles) => { return prevfiles.map((curfile) => { diff --git a/frontend/src/services/CancelAPI.ts b/frontend/src/services/CancelAPI.ts index a162bed83..de3ea9ba0 100644 --- a/frontend/src/services/CancelAPI.ts +++ b/frontend/src/services/CancelAPI.ts @@ -1,6 +1,5 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; import { UserCredentials, commonserverresponse } from '../types'; +import api from '../API/Index'; const cancelAPI = async (filenames: string[], source_types: string[]) => { try { @@ -14,7 +13,7 @@ const cancelAPI = async (filenames: string[], source_types: string[]) => { } formData.append('filenames', JSON.stringify(filenames)); formData.append('source_types', JSON.stringify(source_types)); - const response = await axios.post(`${url()}/cancelled_job`, formData); + const response = await api.post(`/cancelled_job`, formData); return response; } catch (error) { console.log('Error Posting the Question:', error); diff --git a/frontend/src/services/ChunkEntitiesInfo.ts b/frontend/src/services/ChunkEntitiesInfo.ts index 3b4323197..aa133c815 100644 --- a/frontend/src/services/ChunkEntitiesInfo.ts +++ b/frontend/src/services/ChunkEntitiesInfo.ts @@ -1,6 +1,5 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; import { ChatInfo_APIResponse, UserCredentials } from '../types'; +import api from '../API/Index'; const chunkEntitiesAPI = async (userCredentials: UserCredentials, chunk_ids: string) => { try { @@ -10,7 +9,7 @@ const chunkEntitiesAPI = async (userCredentials: UserCredentials, chunk_ids: str formData.append('password', userCredentials?.password ?? ''); formData.append('chunk_ids', chunk_ids); - const response: ChatInfo_APIResponse = await axios.post(`${url()}/chunk_entities`, formData, { + const response: ChatInfo_APIResponse = await api.post(`/chunk_entities`, formData, { headers: { 'Content-Type': 'multipart/form-data', }, diff --git a/frontend/src/services/CommonAPI.ts b/frontend/src/services/CommonAPI.ts index 78d324248..bbae83032 100644 --- a/frontend/src/services/CommonAPI.ts +++ b/frontend/src/services/CommonAPI.ts @@ -1,5 +1,6 @@ -import axios, { AxiosResponse, Method } from 'axios'; +import { AxiosResponse, Method } from 'axios'; import { UserCredentials, FormDataParams } from '../types'; +import api from '../API/Index'; // API Call const apiCall = async ( @@ -16,7 +17,7 @@ const apiCall = async ( for (const key in additionalParams) { formData.append(key, additionalParams[key]); } - const response: AxiosResponse = await axios({ + const response: AxiosResponse = await api({ method: method, url: url, data: formData, diff --git a/frontend/src/services/ConnectAPI.ts b/frontend/src/services/ConnectAPI.ts index 73d997b1e..026c41c44 100644 --- a/frontend/src/services/ConnectAPI.ts +++ b/frontend/src/services/ConnectAPI.ts @@ -1,5 +1,4 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; +import api from '../API/Index'; const connectAPI = async (connectionURI: string, username: string, password: string, database: string) => { try { @@ -8,7 +7,7 @@ const connectAPI = async (connectionURI: string, username: string, password: str formData.append('database', database ?? ''); formData.append('userName', username ?? ''); formData.append('password', password ?? ''); - const response = await axios.post(`${url()}/connect`, formData, { + const response = await api.post(`/connect`, formData, { headers: { 'Content-Type': 'multipart/form-data', }, diff --git a/frontend/src/services/DeleteFiles.ts b/frontend/src/services/DeleteFiles.ts index 36ae28cbd..a86ef187e 100644 --- a/frontend/src/services/DeleteFiles.ts +++ b/frontend/src/services/DeleteFiles.ts @@ -1,6 +1,5 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; import { CustomFile, UserCredentials } from '../types'; +import api from '../API/Index'; const deleteAPI = async (userCredentials: UserCredentials, selectedFiles: CustomFile[], deleteEntities: boolean) => { try { @@ -14,7 +13,7 @@ const deleteAPI = async (userCredentials: UserCredentials, selectedFiles: Custom formData.append('deleteEntities', JSON.stringify(deleteEntities)); formData.append('filenames', JSON.stringify(filenames)); formData.append('source_types', JSON.stringify(source_types)); - const response = await axios.post(`${url()}/delete_document_and_entities`, formData); + const response = await api.post(`/delete_document_and_entities`, formData); return response; } catch (error) { console.log('Error Posting the Question:', error); diff --git a/frontend/src/services/DeleteOrphanNodes.ts b/frontend/src/services/DeleteOrphanNodes.ts index 135dfcdeb..2cebc572c 100644 --- a/frontend/src/services/DeleteOrphanNodes.ts +++ b/frontend/src/services/DeleteOrphanNodes.ts @@ -1,6 +1,5 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; import { UserCredentials } from '../types'; +import api from '../API/Index'; const deleteOrphanAPI = async (userCredentials: UserCredentials, selectedNodes: string[]) => { try { @@ -10,7 +9,7 @@ const deleteOrphanAPI = async (userCredentials: UserCredentials, selectedNodes: formData.append('userName', userCredentials?.userName ?? ''); formData.append('password', userCredentials?.password ?? ''); formData.append('unconnected_entities_list', JSON.stringify(selectedNodes)); - const response = await axios.post(`${url()}/delete_unconnected_nodes`, formData); + const response = await api.post(`/delete_unconnected_nodes`, formData); return response; } catch (error) { console.log('Error Posting the Question:', error); diff --git a/frontend/src/services/GetDuplicateNodes.ts b/frontend/src/services/GetDuplicateNodes.ts index 3cb27a970..b7ea0c426 100644 --- a/frontend/src/services/GetDuplicateNodes.ts +++ b/frontend/src/services/GetDuplicateNodes.ts @@ -1,6 +1,5 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; import { duplicateNodesData, UserCredentials } from '../types'; +import api from '../API/Index'; export const getDuplicateNodes = async (userCredentials: UserCredentials) => { const formData = new FormData(); @@ -9,7 +8,7 @@ export const getDuplicateNodes = async (userCredentials: UserCredentials) => { formData.append('userName', userCredentials?.userName ?? ''); formData.append('password', userCredentials?.password ?? ''); try { - const response = await axios.post(`${url()}/get_duplicate_nodes`, formData); + const response = await api.post(`/get_duplicate_nodes`, formData); return response; } catch (error) { console.log(error); diff --git a/frontend/src/services/GetFiles.ts b/frontend/src/services/GetFiles.ts index fd8d60fba..056a9cc05 100644 --- a/frontend/src/services/GetFiles.ts +++ b/frontend/src/services/GetFiles.ts @@ -1,14 +1,11 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; import { SourceListServerData, UserCredentials } from '../types'; +import api from '../API/Index'; export const getSourceNodes = async (userCredentials: UserCredentials) => { try { const encodedstr = btoa(userCredentials.password); - const response = await axios.get( - `${url()}/sources_list?uri=${userCredentials.uri}&database=${userCredentials.database}&userName=${ - userCredentials.userName - }&password=${encodedstr}` + const response = await api.get( + `/sources_list?uri=${userCredentials.uri}&database=${userCredentials.database}&userName=${userCredentials.userName}&password=${encodedstr}` ); return response; } catch (error) { diff --git a/frontend/src/services/GetNodeLabelsRelTypes.ts b/frontend/src/services/GetNodeLabelsRelTypes.ts index acc05f267..8c7345c2a 100644 --- a/frontend/src/services/GetNodeLabelsRelTypes.ts +++ b/frontend/src/services/GetNodeLabelsRelTypes.ts @@ -1,6 +1,5 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; import { ServerData, UserCredentials } from '../types'; +import api from '../API/Index'; export const getNodeLabelsAndRelTypes = async (userCredentials: UserCredentials) => { const formData = new FormData(); @@ -9,7 +8,7 @@ export const getNodeLabelsAndRelTypes = async (userCredentials: UserCredentials) formData.append('userName', userCredentials?.userName ?? ''); formData.append('password', userCredentials?.password ?? ''); try { - const response = await axios.post(`${url()}/schema`, formData); + const response = await api.post(`/schema`, formData); return response; } catch (error) { console.log(error); diff --git a/frontend/src/services/GetOrphanNodes.ts b/frontend/src/services/GetOrphanNodes.ts index 70cfe8cda..3578214d1 100644 --- a/frontend/src/services/GetOrphanNodes.ts +++ b/frontend/src/services/GetOrphanNodes.ts @@ -1,6 +1,5 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; import { OrphanNodeResponse, UserCredentials } from '../types'; +import api from '../API/Index'; export const getOrphanNodes = async (userCredentials: UserCredentials) => { const formData = new FormData(); @@ -9,7 +8,7 @@ export const getOrphanNodes = async (userCredentials: UserCredentials) => { formData.append('userName', userCredentials?.userName ?? ''); formData.append('password', userCredentials?.password ?? ''); try { - const response = await axios.post(`${url()}/get_unconnected_nodes_list`, formData); + const response = await api.post(`/get_unconnected_nodes_list`, formData); return response; } catch (error) { console.log(error); diff --git a/frontend/src/services/GraphQuery.ts b/frontend/src/services/GraphQuery.ts index 55d22a5ee..f792f4aec 100644 --- a/frontend/src/services/GraphQuery.ts +++ b/frontend/src/services/GraphQuery.ts @@ -1,6 +1,5 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; import { UserCredentials } from '../types'; +import api from '../API/Index'; const graphQueryAPI = async ( userCredentials: UserCredentials, @@ -16,7 +15,7 @@ const graphQueryAPI = async ( formData.append('query_type', query_type ?? 'entities'); formData.append('document_names', JSON.stringify(document_names)); - const response = await axios.post(`${url()}/graph_query`, formData, { + const response = await api.post(`/graph_query`, formData, { headers: { 'Content-Type': 'multipart/form-data', }, diff --git a/frontend/src/services/HealthStatus.ts b/frontend/src/services/HealthStatus.ts index 69a77f0fe..a59badbe0 100644 --- a/frontend/src/services/HealthStatus.ts +++ b/frontend/src/services/HealthStatus.ts @@ -1,9 +1,8 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; +import api from '../API/Index'; const healthStatus = async () => { try { - const healthUrl = `${url()}/health`; - const response = await axios.get(healthUrl); + const healthUrl = `/health`; + const response = await api.get(healthUrl); return response; } catch (error) { console.log('API status error', error); diff --git a/frontend/src/services/MergeDuplicateEntities.ts b/frontend/src/services/MergeDuplicateEntities.ts index ee4e0fffb..1fdb9b387 100644 --- a/frontend/src/services/MergeDuplicateEntities.ts +++ b/frontend/src/services/MergeDuplicateEntities.ts @@ -1,6 +1,5 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; import { commonserverresponse, selectedDuplicateNodes, UserCredentials } from '../types'; +import api from '../API/Index'; const mergeDuplicateNodes = async (userCredentials: UserCredentials, selectedNodes: selectedDuplicateNodes[]) => { try { @@ -10,7 +9,7 @@ const mergeDuplicateNodes = async (userCredentials: UserCredentials, selectedNod formData.append('userName', userCredentials?.userName ?? ''); formData.append('password', userCredentials?.password ?? ''); formData.append('duplicate_nodes_list', JSON.stringify(selectedNodes)); - const response = await axios.post(`${url()}/merge_duplicate_nodes`, formData); + const response = await api.post(`/merge_duplicate_nodes`, formData); return response; } catch (error) { console.log('Error Merging the duplicate nodes:', error); diff --git a/frontend/src/services/PollingAPI.ts b/frontend/src/services/PollingAPI.ts index 08e6a11bb..f14ed0580 100644 --- a/frontend/src/services/PollingAPI.ts +++ b/frontend/src/services/PollingAPI.ts @@ -1,6 +1,5 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; import { PollingAPI_Response, statusupdate } from '../types'; +import api from '../API/Index'; export default async function subscribe( fileName: string, @@ -15,12 +14,12 @@ export default async function subscribe( const MAX_POLLING_ATTEMPTS = 10; let pollingAttempts = 0; - let delay = 2000; + let delay = 1000; while (pollingAttempts < MAX_POLLING_ATTEMPTS) { let currentdelay = delay; - let response: PollingAPI_Response = await axios.get( - `${url()}/document_status/${fileName}?url=${uri}&userName=${username}&password=${encodedstr}&database=${database}` + let response: PollingAPI_Response = await api.get( + `/document_status/${fileName}?url=${uri}&userName=${username}&password=${encodedstr}&database=${database}` ); if (response.data?.file_name?.status === 'Processing') { diff --git a/frontend/src/services/PostProcessing.ts b/frontend/src/services/PostProcessing.ts index 9f45cc6bd..98c94c238 100644 --- a/frontend/src/services/PostProcessing.ts +++ b/frontend/src/services/PostProcessing.ts @@ -1,6 +1,5 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; import { UserCredentials } from '../types'; +import api from '../API/Index'; const postProcessing = async (userCredentials: UserCredentials, taskParam: string[]) => { try { @@ -10,7 +9,7 @@ const postProcessing = async (userCredentials: UserCredentials, taskParam: strin formData.append('userName', userCredentials?.userName ?? ''); formData.append('password', userCredentials?.password ?? ''); formData.append('tasks', JSON.stringify(taskParam)); - const response = await axios.post(`${url()}/post_processing`, formData, { + const response = await api.post(`/post_processing`, formData, { headers: { 'Content-Type': 'multipart/form-data', }, diff --git a/frontend/src/services/QnaAPI.ts b/frontend/src/services/QnaAPI.ts index 931618839..78fa240ba 100644 --- a/frontend/src/services/QnaAPI.ts +++ b/frontend/src/services/QnaAPI.ts @@ -1,6 +1,5 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; import { UserCredentials } from '../types'; +import api from '../API/Index'; export const chatBotAPI = async ( userCredentials: UserCredentials, @@ -22,7 +21,7 @@ export const chatBotAPI = async ( formData.append('mode', mode); formData.append('document_names', JSON.stringify(document_names)); const startTime = Date.now(); - const response = await axios.post(`${url()}/chat_bot`, formData, { + const response = await api.post(`/chat_bot`, formData, { headers: { 'Content-Type': 'multipart/form-data', }, @@ -44,7 +43,7 @@ export const clearChatAPI = async (userCredentials: UserCredentials, session_id: formData.append('userName', userCredentials?.userName ?? ''); formData.append('password', userCredentials?.password ?? ''); formData.append('session_id', session_id); - const response = await axios.post(`${url()}/clear_chat_bot`, formData, { + const response = await api.post(`/clear_chat_bot`, formData, { headers: { 'Content-Type': 'multipart/form-data', }, diff --git a/frontend/src/services/SchemaFromTextAPI.ts b/frontend/src/services/SchemaFromTextAPI.ts index 785fb0d68..3d1984ccf 100644 --- a/frontend/src/services/SchemaFromTextAPI.ts +++ b/frontend/src/services/SchemaFromTextAPI.ts @@ -1,6 +1,5 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; import { ScehmaFromText } from '../types'; +import api from '../API/Index'; export const getNodeLabelsAndRelTypesFromText = async (model: string, inputText: string, isSchemaText: boolean) => { const formData = new FormData(); @@ -9,7 +8,7 @@ export const getNodeLabelsAndRelTypesFromText = async (model: string, inputText: formData.append('is_schema_description_checked', JSON.stringify(isSchemaText)); try { - const response = await axios.post(`${url()}/populate_graph_schema`, formData); + const response = await api.post(`/populate_graph_schema`, formData); return response; } catch (error) { console.log(error); diff --git a/frontend/src/services/URLScan.ts b/frontend/src/services/URLScan.ts index 58ad37dfb..444022934 100644 --- a/frontend/src/services/URLScan.ts +++ b/frontend/src/services/URLScan.ts @@ -1,6 +1,5 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; import { ScanProps, ServerResponse } from '../types'; +import api from '../API/Index'; const urlScanAPI = async (props: ScanProps) => { try { @@ -46,7 +45,7 @@ const urlScanAPI = async (props: ScanProps) => { formData.append('access_token', props.access_token); } - const response: ServerResponse = await axios.post(`${url()}/url/scan`, formData, { + const response: ServerResponse = await api.post(`/url/scan`, formData, { headers: { 'Content-Type': 'multipart/form-data', }, diff --git a/frontend/src/services/vectorIndexCreation.ts b/frontend/src/services/vectorIndexCreation.ts index accf85659..e89767551 100644 --- a/frontend/src/services/vectorIndexCreation.ts +++ b/frontend/src/services/vectorIndexCreation.ts @@ -1,6 +1,5 @@ -import axios from 'axios'; -import { url } from '../utils/Utils'; import { commonserverresponse, UserCredentials } from '../types'; +import api from '../API/Index'; export const createVectorIndex = async (userCredentials: UserCredentials, isVectorIndexExists: boolean) => { const formData = new FormData(); @@ -10,7 +9,7 @@ export const createVectorIndex = async (userCredentials: UserCredentials, isVect formData.append('password', userCredentials?.password ?? ''); formData.append('isVectorIndexExist', JSON.stringify(isVectorIndexExists)); try { - const response = await axios.post(`${url()}/drop_create_vector_index`, formData); + const response = await api.post(`/drop_create_vector_index`, formData); return response; } catch (error) { console.log(error); diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 8e05f632b..5bf076d10 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -259,7 +259,7 @@ export interface GraphViewModalProps { setGraphViewOpen: Dispatch>; viewPoint: string; nodeValues?: ExtendedNode[]; - relationshipValues?: Relationship[]; + relationshipValues?: ExtendedRelationship[]; selectedRows?: CustomFile[] | undefined; } @@ -344,13 +344,13 @@ export type alertStateType = { export type Scheme = Record; export type LabelCount = Record; -interface NodeType extends Partial { - labels?: string[]; -} + export interface LegendChipProps { scheme: Scheme; - title: string; - nodes: NodeType[]; + label: string; + type: 'node' | 'relationship' | 'propertyKey'; + count: number; + onClick: (e: React.MouseEvent) => void; } export interface FileContextProviderProps { children: ReactNode; @@ -578,29 +578,6 @@ export type GraphStatsLabels = Record< } >; -type NodeStyling = { - backgroundColor: string; - borderColor: string; - textColor: string; - caption: string; - diameter: string; -}; - -type RelationStyling = { - fontSize: string; - lineColor: string; - textColorExternal: string; - textColorInternal: string; - caption: string; - padding: string; - width: string; -}; - -export type GraphStyling = { - node: Record>; - relationship: Record>; -}; - export interface ExtendedNode extends Node { labels: string[]; properties: { @@ -610,7 +587,7 @@ export interface ExtendedNode extends Node { } export interface ExtendedRelationship extends Relationship { - labels: string[]; + count: number; } export interface connectionState { openPopUp: boolean; @@ -655,7 +632,7 @@ export interface S3File { } export interface GraphViewButtonProps { nodeValues?: ExtendedNode[]; - relationshipValues?: Relationship[]; + relationshipValues?: ExtendedRelationship[]; } export interface DrawerChatbotProps { isExpanded: boolean; diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index b4781b929..47f1e119f 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -51,15 +51,15 @@ export const llms = 'bedrock_claude_3_5_sonnet', ]; -export const defaultLLM = llms?.includes('openai-gpt-4o-mini') - ? 'openai-gpt-4o-mini' +export const defaultLLM = llms?.includes('openai-gpt-4o') + ? 'openai-gpt-4o' : llms?.includes('gemini-1.0-pro') ? 'gemini-1.0-pro' : 'diffbot'; export const chatModes = process.env?.VITE_CHAT_MODES?.trim() != '' ? process.env.VITE_CHAT_MODES?.split(',') - : ['vector', 'graph', 'graph+vector', 'hybrid', 'hybrid+graph']; + : ['vector', 'graph', 'graph+vector', 'fulltext', 'graph+vector+fulltext']; export const chunkSize = process.env.VITE_CHUNK_SIZE ? parseInt(process.env.VITE_CHUNK_SIZE) : 1 * 1024 * 1024; export const timeperpage = process.env.VITE_TIME_PER_PAGE ? parseInt(process.env.VITE_TIME_PER_PAGE) : 50; export const timePerByte = 0.2; @@ -231,4 +231,8 @@ export const graphLabels = { totalNodes: 'Total Nodes', noEntities: 'No Entities Found', selectCheckbox: 'Select atleast one checkbox for graph view', + totalRelationships: 'Total Relationships', + nodeSize: 30, }; + +export const RESULT_STEP_SIZE = 25; diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index 9745993f6..0b8b05841 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -1,6 +1,6 @@ import { calcWordColor } from '@neo4j-devtools/word-color'; import type { Relationship } from '@neo4j-nvl/base'; -import { Entity, ExtendedNode, GraphType, Messages, Scheme } from '../types'; +import { Entity, ExtendedNode, ExtendedRelationship, GraphType, Messages, Scheme } from '../types'; // Get the Url export const url = () => { @@ -130,7 +130,7 @@ export function extractPdfFileName(url: string): string { return decodedFileName; } -export const processGraphData = (neoNodes: ExtendedNode[], neoRels: Relationship[]) => { +export const processGraphData = (neoNodes: ExtendedNode[], neoRels: ExtendedRelationship[]) => { const schemeVal: Scheme = {}; let iterator = 0; const labels: string[] = neoNodes.map((f: any) => f.labels); @@ -239,3 +239,9 @@ export const parseEntity = (entity: Entity) => { export const titleCheck = (title: string) => { return title === 'Chunk' || title === 'Document'; }; + +export const sortAlphabetically = (a: Relationship, b: Relationship) => { + const captionOne = a.caption?.toLowerCase() || ''; + const captionTwo = b.caption?.toLowerCase() || ''; + return captionOne.localeCompare(captionTwo); +}; diff --git a/frontend/yarn.lock b/frontend/yarn.lock index c91c34832..3915845ef 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -6614,4 +6614,4 @@ yocto-queue@^0.1.0: zwitch@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-2.0.4.tgz#c827d4b0acb76fc3e685a4c6ec2902d51070e9d7" - integrity sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A== + integrity sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A== \ No newline at end of file From 8baedb01613eaa492ad02d0789c0134de66873c9 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Tue, 3 Sep 2024 12:45:43 +0000 Subject: [PATCH 040/292] modified the summary creation --- backend/src/communities.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/communities.py b/backend/src/communities.py index 1c670fff1..ec5199150 100644 --- a/backend/src/communities.py +++ b/backend/src/communities.py @@ -266,7 +266,7 @@ def create_community_summaries(gds, model): summaries = [] with ThreadPoolExecutor() as executor: - futures = [executor.submit(process_community_info, community, community_chain) for _, community in community_info_list.items()] + futures = [executor.submit(process_community_info, community, community_chain) for community in community_info_list.to_dict(orient="records")] for future in as_completed(futures): result = future.result() @@ -282,7 +282,7 @@ def create_community_summaries(gds, model): parent_summaries = [] with ThreadPoolExecutor() as executor: - futures = [executor.submit(process_community_info, community, parent_community_chain, is_parent=True) for _, community in parent_community_info.items()] + futures = [executor.submit(process_community_info, community, parent_community_chain, is_parent=True) for community in parent_community_info.to_dict(orient="records")] for future in as_completed(futures): result = future.result() From c666c368b1ce6c09d06d90f82451fdce7ad56629 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Tue, 3 Sep 2024 12:48:02 +0000 Subject: [PATCH 041/292] fixed the summary creation --- backend/src/communities.py | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/src/communities.py b/backend/src/communities.py index ec5199150..7086a4786 100644 --- a/backend/src/communities.py +++ b/backend/src/communities.py @@ -225,7 +225,6 @@ def get_community_chain(model, is_parent=False,community_template=COMMUNITY_TEMP logging.error(f"Failed to create community chain: {e}") raise - def prepare_string(community_data): try: nodes_description = "Nodes are:\n" From c15932207fdce246ceaa872f40fecb28101061cb Mon Sep 17 00:00:00 2001 From: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Date: Tue, 3 Sep 2024 13:55:36 +0000 Subject: [PATCH 042/292] Configuration change. Update LLM models and remove --preload from docker file --- backend/Dockerfile | 2 +- backend/src/document_sources/wikipedia.py | 2 +- backend/src/shared/constants.py | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index ff46b33e5..5249ac53c 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -21,4 +21,4 @@ RUN pip install -r requirements.txt # Copy application code COPY . /code # Set command -CMD ["gunicorn", "score:app", "--workers", "8","--preload","--threads", "8", "--worker-class", "uvicorn.workers.UvicornWorker", "--bind", "0.0.0.0:8000", "--timeout", "300"] +CMD ["gunicorn", "score:app", "--workers", "8","--threads", "8", "--worker-class", "uvicorn.workers.UvicornWorker", "--bind", "0.0.0.0:8000", "--timeout", "300"] diff --git a/backend/src/document_sources/wikipedia.py b/backend/src/document_sources/wikipedia.py index 1c8b32a33..71820a69e 100644 --- a/backend/src/document_sources/wikipedia.py +++ b/backend/src/document_sources/wikipedia.py @@ -4,7 +4,7 @@ def get_documents_from_Wikipedia(wiki_query:str, language:str): try: - pages = WikipediaLoader(query=wiki_query.strip(), lang=language, load_max_docs=1, load_all_available_meta=False).load() + pages = WikipediaLoader(query=wiki_query.strip(), lang=language, load_all_available_meta=False).load() file_name = wiki_query.strip() logging.info(f"Total Pages from Wikipedia = {len(pages)}") return file_name, pages diff --git a/backend/src/shared/constants.py b/backend/src/shared/constants.py index c5f8e98a4..b67e92730 100644 --- a/backend/src/shared/constants.py +++ b/backend/src/shared/constants.py @@ -1,11 +1,11 @@ MODEL_VERSIONS = { - "openai-gpt-3.5": "gpt-3.5-turbo-16k", + "openai-gpt-3.5": "gpt-3.5-turbo-0125", "gemini-1.0-pro": "gemini-1.0-pro-001", "gemini-1.5-pro": "gemini-1.5-pro-preview-0514", - "openai-gpt-4": "gpt-4-0125-preview", - "diffbot" : "gpt-4o", - "openai-gpt-4o-mini": "gpt-4o-mini", - "openai-gpt-4o":"gpt-4o", + "openai-gpt-4": "gpt-4-turbo-2024-04-09", + "diffbot" : "gpt-4-turbo-2024-04-09", + "openai-gpt-4o-mini": "gpt-4o-mini-2024-07-18", + "openai-gpt-4o":"gpt-4o-2024-08-06", "groq-llama3" : "llama3-70b-8192" } OPENAI_MODELS = ["openai-gpt-3.5", "openai-gpt-4o", "openai-gpt-4o-mini"] From e08aeab10816f65a606e9fdfa547e6d1b0427a5d Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Wed, 4 Sep 2024 14:22:12 +0530 Subject: [PATCH 043/292] Retry processing (#698) * Remove TotalPages when save file on local (#684) * file_name reference and verify_ssl issue fixed (#683) * User flow changes for recreating supported vector index (#682) * removed the if check * Add one more check for create vector index when chunks are exist without embeddings * removed local files * condition changes * chunks exists check * chunk exists without embeddings check * vector Index issue fixed * vector index with different dimension * Update graphDB_dataAccess.py --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Remove TotalPages when save file on local (#684) * file_name reference and verify_ssl issue fixed (#683) * User flow changes for recreating supported vector index (#682) * removed the if check * Add one more check for create vector index when chunks are exist without embeddings * removed local files * condition changes * chunks exists check * chunk exists without embeddings check * vector Index issue fixed * vector index with different dimension * Update graphDB_dataAccess.py --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Reapply "Dockerfile changes with VITE label" This reverts commit a83e0855fbf54d2b5af009d96c4edf0bcd7ab84a. * Revert "Dockerfile changes with VITE label" This reverts commit 2840ebc9e6156c51465a9f54be72ca2d014147c2. * Concurrent processing of files (#665) * Update README.md * Droped the old vector index (#652) * added cypher_queries and llm chatbot files * updated llm-chatbot-python * added llm-chatbot-python * updated llm-chatbot-python folder * Added chatbot "hybrid " mode use case * added the concurrent file processing * page refresh scenario * fixed waiting files processing issue in refresh scenario * removed boolean param * fixed processedCount issue * checkbox with waiting check * fixed the refresh scenario with processing files * processing files check * server side error * processing file count check for processing files less than batch size * processing count check to handle allselected files * created helper functions * code improvements * __ changes (#656) * DiffbotGraphTransformer doesn't need an LLMGraphTransformer (#659) Co-authored-by: jeromechoo * Removed experiments/llm-chatbot-python folder from DEV branch * redcued the password clear timeout * Removed experiments/Cypher_Queries.ipynb file from DEV branch * disabled the closed button on banner and connection dialog while API is in pending state * update delete query with entities * node id check (#663) * Status source and type filtering (#664) * status source * Name change * type change * rollback to previous working nvl version * added the alert * add BATCH_SIZE to docker * temp fixes for 0.3.1 * alert fix for less than batch size processing * new virtual env * added Hybrid Chat modes (#670) * Rename the function #657 * label and checkboxes placement changes (#675) * label and checkboxes placement changes * checkbox placement changes * Graph node filename check * env fixes with latest nvl libraries * format fixes * removed local files * Remove TotalPages when save file on local (#684) * file_name reference and verify_ssl issue fixed (#683) * User flow changes for recreating supported vector index (#682) * removed the if check * Add one more check for create vector index when chunks are exist without embeddings * removed local files * condition changes * chunks exists check * chunk exists without embeddings check * vector Index issue fixed * vector index with different dimension * Update graphDB_dataAccess.py --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * ndl changes * label and checkboxes placement changes (#675) * label and checkboxes placement changes * checkbox placement changes * env fixes with latest nvl libraries * format fixes * User flow changes for recreating supported vector index (#682) * removed the if check * Add one more check for create vector index when chunks are exist without embeddings * removed local files * condition changes * chunks exists check * chunk exists without embeddings check * vector Index issue fixed * vector index with different dimension * Update graphDB_dataAccess.py --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * env fixes with latest nvl libraries * format fixes * User flow changes for recreating supported vector index (#682) * removed the if check * Add one more check for create vector index when chunks are exist without embeddings * removed local files * condition changes * chunks exists check * chunk exists without embeddings check * vector Index issue fixed * vector index with different dimension * Update graphDB_dataAccess.py --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Status source and type filtering (#664) * status source * Name change * type change * added the alert * temp fixes for 0.3.1 * label and checkboxes placement changes (#675) * label and checkboxes placement changes * checkbox placement changes * env fixes with latest nvl libraries * format fixes * User flow changes for recreating supported vector index (#682) * removed the if check * Add one more check for create vector index when chunks are exist without embeddings * removed local files * condition changes * chunks exists check * chunk exists without embeddings check * vector Index issue fixed * vector index with different dimension * Update graphDB_dataAccess.py --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * ndl changes * env fixes with latest nvl libraries * format fixes * User flow changes for recreating supported vector index (#682) * removed the if check * Add one more check for create vector index when chunks are exist without embeddings * removed local files * condition changes * chunks exists check * chunk exists without embeddings check * vector Index issue fixed * vector index with different dimension * Update graphDB_dataAccess.py --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * env fixes with latest nvl libraries * format fixes * User flow changes for recreating supported vector index (#682) * removed the if check * Add one more check for create vector index when chunks are exist without embeddings * removed local files * condition changes * chunks exists check * chunk exists without embeddings check * vector Index issue fixed * vector index with different dimension * Update graphDB_dataAccess.py --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * added cypher_queries and llm chatbot files * updated llm-chatbot-python * added llm-chatbot-python * updated llm-chatbot-python folder * page refresh scenario * fixed waiting files processing issue in refresh scenario * Removed experiments/llm-chatbot-python folder from DEV branch * disabled the closed button on banner and connection dialog while API is in pending state * node id check (#663) * Status source and type filtering (#664) * status source * Name change * type change * rollback to previous working nvl version * added the alert * temp fixes for 0.3.1 * label and checkboxes placement changes (#675) * label and checkboxes placement changes * checkbox placement changes * env fixes with latest nvl libraries * format fixes * User flow changes for recreating supported vector index (#682) * removed the if check * Add one more check for create vector index when chunks are exist without embeddings * removed local files * condition changes * chunks exists check * chunk exists without embeddings check * vector Index issue fixed * vector index with different dimension * Update graphDB_dataAccess.py --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * ndl changes * env fixes with latest nvl libraries * format fixes * User flow changes for recreating supported vector index (#682) * removed the if check * Add one more check for create vector index when chunks are exist without embeddings * removed local files * condition changes * chunks exists check * chunk exists without embeddings check * vector Index issue fixed * vector index with different dimension * Update graphDB_dataAccess.py --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * env fixes with latest nvl libraries * format fixes * User flow changes for recreating supported vector index (#682) * removed the if check * Add one more check for create vector index when chunks are exist without embeddings * removed local files * condition changes * chunks exists check * chunk exists without embeddings check * vector Index issue fixed * vector index with different dimension * Update graphDB_dataAccess.py --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Status source and type filtering (#664) * status source * Name change * type change * added the alert * temp fixes for 0.3.1 * label and checkboxes placement changes (#675) * label and checkboxes placement changes * checkbox placement changes * env fixes with latest nvl libraries * format fixes * User flow changes for recreating supported vector index (#682) * removed the if check * Add one more check for create vector index when chunks are exist without embeddings * removed local files * condition changes * chunks exists check * chunk exists without embeddings check * vector Index issue fixed * vector index with different dimension * Update graphDB_dataAccess.py --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * ndl changes * env fixes with latest nvl libraries * format fixes * User flow changes for recreating supported vector index (#682) * removed the if check * Add one more check for create vector index when chunks are exist without embeddings * removed local files * condition changes * chunks exists check * chunk exists without embeddings check * vector Index issue fixed * vector index with different dimension * Update graphDB_dataAccess.py --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * env fixes with latest nvl libraries * format fixes * User flow changes for recreating supported vector index (#682) * removed the if check * Add one more check for create vector index when chunks are exist without embeddings * removed local files * condition changes * chunks exists check * chunk exists without embeddings check * vector Index issue fixed * vector index with different dimension * Update graphDB_dataAccess.py --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * property spell fix --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Jayanth T Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Jerome Choo Co-authored-by: jeromechoo Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * env changes * format fixes * set retry status * retry processing backend * added the retry icon on rows * vite changes in docker compose * added retry dialog * Integrated the Retry processing API * Integrated the Extract API fro retry processing * Integrated ndl toast component * replaced foreach with normal for loop for better performance * types improvements * used toast component * spell fix * Issue fixed * processing changes in main * function closing fix * retry processing issue fixed * autoclosing the retry popup on retry api success * removed the retry if check * resetting the node and relationship count on retry * added the enter key events on the popups * fixed wikipedia icon on large file alert popup * setting nodes to 0 and start from last processed chunk logic changes * Retry Popup fixes * status changes for upload failed scenario * kept condition specific * changed status to reprocess from retry * Reprocess wording changes * tooltip changes * wordings and size changes * Changed status to Reprocess --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Jayanth T Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: Jerome Choo Co-authored-by: jeromechoo Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> --- backend/score.py | 33 +- backend/src/entities/source_node.py | 1 + backend/src/graphDB_dataAccess.py | 11 +- backend/src/main.py | 218 ++++++++---- backend/src/shared/constants.py | 39 +++ frontend/example.env | 2 +- frontend/src/App.tsx | 4 +- .../src/components/ChatBot/ChatInfoModal.tsx | 5 +- frontend/src/components/ChatBot/Chatbot.tsx | 10 +- .../src/components/ChatBot/Info/InfoModal.tsx | 5 +- frontend/src/components/Content.tsx | 319 ++++++++++-------- .../components/DataSources/AWS/S3Modal.tsx | 119 ++++--- .../components/DataSources/GCS/GCSModal.tsx | 180 +++++----- .../components/DataSources/Local/DropZone.tsx | 61 +--- .../Local/DropZoneForSmallLayouts.tsx | 59 ++-- frontend/src/components/FileTable.tsx | 215 +++++------- frontend/src/components/Layout/PageLayout.tsx | 35 +- .../DeleteTabForOrphanNodes/index.tsx | 5 +- .../EntityExtractionSetting.tsx | 22 +- .../Popups/GraphEnhancementDialog/index.tsx | 6 - .../LargeFilePopUp/ConfirmationDialog.tsx | 5 +- .../Popups/LargeFilePopUp/LargeFilesAlert.tsx | 3 +- .../Popups/RetryConfirmation/Index.tsx | 84 +++++ .../Popups/Settings/SchemaFromText.tsx | 22 +- .../Popups/Settings/SettingModal.tsx | 16 +- .../WebSources/CustomSourceInput.tsx | 5 + frontend/src/hooks/useSourceInput.tsx | 65 ++-- frontend/src/services/CommonAPI.ts | 2 +- frontend/src/services/retry.ts | 23 ++ frontend/src/types.ts | 85 ++--- frontend/src/utils/Constants.ts | 6 +- frontend/src/utils/FileAPI.ts | 7 + frontend/src/utils/Utils.ts | 50 ++- frontend/src/utils/toasts.ts | 22 ++ frontend/yarn.lock | 1 + 35 files changed, 1006 insertions(+), 739 deletions(-) create mode 100644 frontend/src/components/Popups/RetryConfirmation/Index.tsx create mode 100644 frontend/src/services/retry.ts create mode 100644 frontend/src/utils/toasts.ts diff --git a/backend/score.py b/backend/score.py index 00650b56e..08ea9a6b2 100644 --- a/backend/score.py +++ b/backend/score.py @@ -137,7 +137,8 @@ async def extract_knowledge_graph_from_file( allowedNodes=Form(None), allowedRelationship=Form(None), language=Form(None), - access_token=Form(None) + access_token=Form(None), + retry_condition=Form(None) ): """ Calls 'extract_graph_from_file' in a new thread to create Neo4jGraph from a @@ -161,30 +162,30 @@ async def extract_knowledge_graph_from_file( merged_file_path = os.path.join(MERGED_DIR,file_name) logging.info(f'File path:{merged_file_path}') result = await asyncio.to_thread( - extract_graph_from_file_local_file, uri, userName, password, database, model, merged_file_path, file_name, allowedNodes, allowedRelationship) + extract_graph_from_file_local_file, uri, userName, password, database, model, merged_file_path, file_name, allowedNodes, allowedRelationship, retry_condition) elif source_type == 's3 bucket' and source_url: result = await asyncio.to_thread( - extract_graph_from_file_s3, uri, userName, password, database, model, source_url, aws_access_key_id, aws_secret_access_key, allowedNodes, allowedRelationship) + extract_graph_from_file_s3, uri, userName, password, database, model, source_url, aws_access_key_id, aws_secret_access_key, file_name, allowedNodes, allowedRelationship, retry_condition) elif source_type == 'web-url': result = await asyncio.to_thread( - extract_graph_from_web_page, uri, userName, password, database, model, source_url, allowedNodes, allowedRelationship) + extract_graph_from_web_page, uri, userName, password, database, model, source_url, file_name, allowedNodes, allowedRelationship, retry_condition) elif source_type == 'youtube' and source_url: result = await asyncio.to_thread( - extract_graph_from_file_youtube, uri, userName, password, database, model, source_url, allowedNodes, allowedRelationship) + extract_graph_from_file_youtube, uri, userName, password, database, model, source_url, file_name, allowedNodes, allowedRelationship, retry_condition) elif source_type == 'Wikipedia' and wiki_query: result = await asyncio.to_thread( - extract_graph_from_file_Wikipedia, uri, userName, password, database, model, wiki_query, max_sources, language, allowedNodes, allowedRelationship) + extract_graph_from_file_Wikipedia, uri, userName, password, database, model, wiki_query, language, file_name, allowedNodes, allowedRelationship, retry_condition) elif source_type == 'gcs bucket' and gcs_bucket_name: result = await asyncio.to_thread( - extract_graph_from_file_gcs, uri, userName, password, database, model, gcs_project_id, gcs_bucket_name, gcs_bucket_folder, gcs_blob_filename, access_token, allowedNodes, allowedRelationship) + extract_graph_from_file_gcs, uri, userName, password, database, model, gcs_project_id, gcs_bucket_name, gcs_bucket_folder, gcs_blob_filename, access_token, file_name, allowedNodes, allowedRelationship, retry_condition) else: return create_api_response('Failed',message='source_type is other than accepted source') - + if result is not None: result['db_url'] = uri result['api_name'] = 'extract' @@ -626,6 +627,22 @@ async def merge_duplicate_nodes(uri=Form(), userName=Form(), password=Form(), da return create_api_response(job_status, message=message, error=error_message) finally: gc.collect() + +@app.post("/retry_processing") +async def retry_processing(uri=Form(), userName=Form(), password=Form(), database=Form(), file_name=Form(), retry_condition=Form()): + try: + graph = create_graph_database_connection(uri, userName, password, database) + await asyncio.to_thread(set_status_retry, graph,file_name,retry_condition) + #set_status_retry(graph,file_name,retry_condition) + return create_api_response('Success',message=f"Status set to Reprocess for filename : {file_name}") + except Exception as e: + job_status = "Failed" + message="Unable to set status to Retry" + error_message = str(e) + logging.exception(f'{error_message}') + return create_api_response(job_status, message=message, error=error_message) + finally: + gc.collect() if __name__ == "__main__": uvicorn.run(app) diff --git a/backend/src/entities/source_node.py b/backend/src/entities/source_node.py index aa0e73faa..1a1c70487 100644 --- a/backend/src/entities/source_node.py +++ b/backend/src/entities/source_node.py @@ -24,3 +24,4 @@ class sourceNode: is_cancelled:bool=None processed_chunk:int=None access_token:str=None + retry_condition:str=None diff --git a/backend/src/graphDB_dataAccess.py b/backend/src/graphDB_dataAccess.py index c77a1e773..c1eaaa190 100644 --- a/backend/src/graphDB_dataAccess.py +++ b/backend/src/graphDB_dataAccess.py @@ -71,10 +71,10 @@ def update_source_node(self, obj_source_node:sourceNode): if obj_source_node.processing_time is not None and obj_source_node.processing_time != 0: params['processingTime'] = round(obj_source_node.processing_time.total_seconds(),2) - if obj_source_node.node_count is not None and obj_source_node.node_count != 0: + if obj_source_node.node_count is not None : params['nodeCount'] = obj_source_node.node_count - if obj_source_node.relationship_count is not None and obj_source_node.relationship_count != 0: + if obj_source_node.relationship_count is not None : params['relationshipCount'] = obj_source_node.relationship_count if obj_source_node.model is not None and obj_source_node.model != '': @@ -86,11 +86,14 @@ def update_source_node(self, obj_source_node:sourceNode): if obj_source_node.total_chunks is not None and obj_source_node.total_chunks != 0: params['total_chunks'] = obj_source_node.total_chunks - if obj_source_node.is_cancelled is not None and obj_source_node.is_cancelled != False: + if obj_source_node.is_cancelled is not None: params['is_cancelled'] = obj_source_node.is_cancelled - if obj_source_node.processed_chunk is not None and obj_source_node.processed_chunk != 0: + if obj_source_node.processed_chunk is not None : params['processed_chunk'] = obj_source_node.processed_chunk + + if obj_source_node.retry_condition is not None : + params['retry_condition'] = obj_source_node.retry_condition param= {"props":params} diff --git a/backend/src/main.py b/backend/src/main.py index a7d5058a0..3a88f1eb3 100644 --- a/backend/src/main.py +++ b/backend/src/main.py @@ -1,5 +1,11 @@ from langchain_community.graphs import Neo4jGraph -from src.shared.constants import BUCKET_UPLOAD, PROJECT_ID +from src.shared.constants import (BUCKET_UPLOAD, PROJECT_ID, QUERY_TO_GET_CHUNKS, + QUERY_TO_DELETE_EXISTING_ENTITIES, + QUERY_TO_GET_LAST_PROCESSED_CHUNK_POSITION, + QUERY_TO_GET_LAST_PROCESSED_CHUNK_WITHOUT_ENTITY, + START_FROM_BEGINNING, + START_FROM_LAST_PROCESSED_POSITION, + DELETE_ENTITIES_AND_START_FROM_BEGINNING) from src.shared.schema_extraction import schema_extraction_from_text from dotenv import load_dotenv from datetime import datetime @@ -182,68 +188,75 @@ def create_source_node_graph_url_wikipedia(graph, model, wiki_query, source_type lst_file_name.append({'fileName':obj_source_node.file_name,'fileSize':obj_source_node.file_size,'url':obj_source_node.url, 'language':obj_source_node.language, 'status':'Success'}) return lst_file_name,success_count,failed_count -def extract_graph_from_file_local_file(uri, userName, password, database, model, merged_file_path, fileName, allowedNodes, allowedRelationship): +def extract_graph_from_file_local_file(uri, userName, password, database, model, merged_file_path, fileName, allowedNodes, allowedRelationship, retry_condition): logging.info(f'Process file name :{fileName}') - gcs_file_cache = os.environ.get('GCS_FILE_CACHE') - if gcs_file_cache == 'True': - folder_name = create_gcs_bucket_folder_name_hashed(uri, fileName) - file_name, pages = get_documents_from_gcs( PROJECT_ID, BUCKET_UPLOAD, folder_name, fileName) + if retry_condition is None: + gcs_file_cache = os.environ.get('GCS_FILE_CACHE') + if gcs_file_cache == 'True': + folder_name = create_gcs_bucket_folder_name_hashed(uri, fileName) + file_name, pages = get_documents_from_gcs( PROJECT_ID, BUCKET_UPLOAD, folder_name, fileName) + else: + file_name, pages, file_extension = get_documents_from_file_by_path(merged_file_path,fileName) + if pages==None or len(pages)==0: + raise Exception(f'File content is not available for file : {file_name}') + return processing_source(uri, userName, password, database, model, file_name, pages, allowedNodes, allowedRelationship, True, merged_file_path) else: - file_name, pages, file_extension = get_documents_from_file_by_path(merged_file_path,fileName) - if pages==None or len(pages)==0: - raise Exception(f'File content is not available for file : {file_name}') - - return processing_source(uri, userName, password, database, model, file_name, pages, allowedNodes, allowedRelationship, True, merged_file_path) - -def extract_graph_from_file_s3(uri, userName, password, database, model, source_url, aws_access_key_id, aws_secret_access_key, allowedNodes, allowedRelationship): + return processing_source(uri, userName, password, database, model, fileName, [], allowedNodes, allowedRelationship, True, merged_file_path, retry_condition) + +def extract_graph_from_file_s3(uri, userName, password, database, model, source_url, aws_access_key_id, aws_secret_access_key, file_name, allowedNodes, allowedRelationship, retry_condition): + if retry_condition is None: + if(aws_access_key_id==None or aws_secret_access_key==None): + raise Exception('Please provide AWS access and secret keys') + else: + logging.info("Insert in S3 Block") + file_name, pages = get_documents_from_s3(source_url, aws_access_key_id, aws_secret_access_key) - if(aws_access_key_id==None or aws_secret_access_key==None): - raise Exception('Please provide AWS access and secret keys') + if pages==None or len(pages)==0: + raise Exception(f'File content is not available for file : {file_name}') + return processing_source(uri, userName, password, database, model, file_name, pages, allowedNodes, allowedRelationship) else: - logging.info("Insert in S3 Block") - file_name, pages = get_documents_from_s3(source_url, aws_access_key_id, aws_secret_access_key) - - if pages==None or len(pages)==0: - raise Exception(f'File content is not available for file : {file_name}') - - return processing_source(uri, userName, password, database, model, file_name, pages, allowedNodes, allowedRelationship) - -def extract_graph_from_web_page(uri, userName, password, database, model, source_url, allowedNodes, allowedRelationship): - - file_name, pages = get_documents_from_web_page(source_url) - - if pages==None or len(pages)==0: - raise Exception(f'Content is not available for given URL : {file_name}') - - return processing_source(uri, userName, password, database, model, file_name, pages, allowedNodes, allowedRelationship) - -def extract_graph_from_file_youtube(uri, userName, password, database, model, source_url, allowedNodes, allowedRelationship): + return processing_source(uri, userName, password, database, model, file_name, [], allowedNodes, allowedRelationship, retry_condition=retry_condition) - file_name, pages = get_documents_from_youtube(source_url) - - if pages==None or len(pages)==0: - raise Exception(f'Youtube transcript is not available for file : {file_name}') - - return processing_source(uri, userName, password, database, model, file_name, pages, allowedNodes, allowedRelationship) - -def extract_graph_from_file_Wikipedia(uri, userName, password, database, model, wiki_query, max_sources, language, allowedNodes, allowedRelationship): +def extract_graph_from_web_page(uri, userName, password, database, model, source_url, file_name, allowedNodes, allowedRelationship, retry_condition): + if retry_condition is None: + file_name, pages = get_documents_from_web_page(source_url) - file_name, pages = get_documents_from_Wikipedia(wiki_query, language) - if pages==None or len(pages)==0: - raise Exception(f'Wikipedia page is not available for file : {file_name}') - - return processing_source(uri, userName, password, database, model, file_name, pages, allowedNodes, allowedRelationship) - -def extract_graph_from_file_gcs(uri, userName, password, database, model, gcs_project_id, gcs_bucket_name, gcs_bucket_folder, gcs_blob_filename, access_token, allowedNodes, allowedRelationship): - - file_name, pages = get_documents_from_gcs(gcs_project_id, gcs_bucket_name, gcs_bucket_folder, gcs_blob_filename, access_token) - if pages==None or len(pages)==0: - raise Exception(f'File content is not available for file : {file_name}') + if pages==None or len(pages)==0: + raise Exception(f'Content is not available for given URL : {file_name}') + return processing_source(uri, userName, password, database, model, file_name, pages, allowedNodes, allowedRelationship) + else: + return processing_source(uri, userName, password, database, model, file_name, [], allowedNodes, allowedRelationship, retry_condition=retry_condition) + +def extract_graph_from_file_youtube(uri, userName, password, database, model, source_url, file_name, allowedNodes, allowedRelationship, retry_condition): + if retry_condition is None: + file_name, pages = get_documents_from_youtube(source_url) - return processing_source(uri, userName, password, database, model, file_name, pages, allowedNodes, allowedRelationship) + if pages==None or len(pages)==0: + raise Exception(f'Youtube transcript is not available for file : {file_name}') + return processing_source(uri, userName, password, database, model, file_name, pages, allowedNodes, allowedRelationship) + else: + return processing_source(uri, userName, password, database, model, file_name, [], allowedNodes, allowedRelationship, retry_condition=retry_condition) + +def extract_graph_from_file_Wikipedia(uri, userName, password, database, model, wiki_query, language, file_name, allowedNodes, allowedRelationship, retry_condition): + if retry_condition is None: + file_name, pages = get_documents_from_Wikipedia(wiki_query, language) + if pages==None or len(pages)==0: + raise Exception(f'Wikipedia page is not available for file : {file_name}') + return processing_source(uri, userName, password, database, model, file_name, pages, allowedNodes, allowedRelationship) + else: + return processing_source(uri, userName, password, database, model, file_name,[], allowedNodes, allowedRelationship, retry_condition=retry_condition) -def processing_source(uri, userName, password, database, model, file_name, pages, allowedNodes, allowedRelationship, is_uploaded_from_local=None, merged_file_path=None): +def extract_graph_from_file_gcs(uri, userName, password, database, model, gcs_project_id, gcs_bucket_name, gcs_bucket_folder, gcs_blob_filename, access_token, file_name, allowedNodes, allowedRelationship, retry_condition): + if retry_condition is None: + file_name, pages = get_documents_from_gcs(gcs_project_id, gcs_bucket_name, gcs_bucket_folder, gcs_blob_filename, access_token) + if pages==None or len(pages)==0: + raise Exception(f'File content is not available for file : {file_name}') + return processing_source(uri, userName, password, database, model, file_name, pages, allowedNodes, allowedRelationship) + else: + return processing_source(uri, userName, password, database, model, file_name, [], allowedNodes, allowedRelationship, retry_condition=retry_condition) + +def processing_source(uri, userName, password, database, model, file_name, pages, allowedNodes, allowedRelationship, is_uploaded_from_local=None, merged_file_path=None, retry_condition=None): """ Extracts a Neo4jGraph from a PDF file based on the model. @@ -263,31 +276,27 @@ def processing_source(uri, userName, password, database, model, file_name, pages graph = create_graph_database_connection(uri, userName, password, database) graphDb_data_Access = graphDBdataAccess(graph) + total_chunks, chunkId_chunkDoc_list = get_chunkId_chunkDoc_list(graph, file_name, pages, retry_condition) result = graphDb_data_Access.get_current_status_document_node(file_name) - print(result) - logging.info("Break down file into chunks") - bad_chars = ['"', "\n", "'"] - for i in range(0,len(pages)): - text = pages[i].page_content - for j in bad_chars: - if j == '\n': - text = text.replace(j, ' ') - else: - text = text.replace(j, '') - pages[i]=Document(page_content=str(text), metadata=pages[i].metadata) - create_chunks_obj = CreateChunksofDocument(pages, graph) - chunks = create_chunks_obj.split_file_into_chunks() - chunkId_chunkDoc_list = create_relation_between_chunks(graph,file_name,chunks) - + + select_chunks_with_retry=0 + node_count = 0 + rel_count = 0 + if len(result) > 0: if result[0]['Status'] != 'Processing': obj_source_node = sourceNode() status = "Processing" obj_source_node.file_name = file_name obj_source_node.status = status - obj_source_node.total_chunks = len(chunks) + obj_source_node.total_chunks = total_chunks obj_source_node.total_pages = len(pages) obj_source_node.model = model + if retry_condition == START_FROM_LAST_PROCESSED_POSITION: + node_count = result[0]['nodeCount'] + rel_count = result[0]['relationshipCount'] + select_chunks_with_retry = result[0]['processed_chunk'] + obj_source_node.processed_chunk = 0+select_chunks_with_retry logging.info(file_name) logging.info(obj_source_node) graphDb_data_Access.update_source_node(obj_source_node) @@ -297,21 +306,22 @@ def processing_source(uri, userName, password, database, model, file_name, pages # selected_chunks = [] is_cancelled_status = False job_status = "Completed" - node_count = 0 - rel_count = 0 + for i in range(0, len(chunkId_chunkDoc_list), update_graph_chunk_processed): select_chunks_upto = i+update_graph_chunk_processed logging.info(f'Selected Chunks upto: {select_chunks_upto}') if len(chunkId_chunkDoc_list) <= select_chunks_upto: select_chunks_upto = len(chunkId_chunkDoc_list) selected_chunks = chunkId_chunkDoc_list[i:select_chunks_upto] + + logging.info(f"select_chunks_upto={select_chunks_upto}, update_graph_chunk_processed={update_graph_chunk_processed}, selected_chunks={len(selected_chunks)}") result = graphDb_data_Access.get_current_status_document_node(file_name) is_cancelled_status = result[0]['is_cancelled'] logging.info(f"Value of is_cancelled : {result[0]['is_cancelled']}") if bool(is_cancelled_status) == True: job_status = "Cancelled" logging.info('Exit from running loop of processing file') - exit + break else: node_count,rel_count = processing_chunks(selected_chunks,graph,uri, userName, password, database,file_name,model,allowedNodes,allowedRelationship,node_count, rel_count) end_time = datetime.now() @@ -321,8 +331,8 @@ def processing_source(uri, userName, password, database, model, file_name, pages obj_source_node.file_name = file_name obj_source_node.updated_at = end_time obj_source_node.processing_time = processed_time + obj_source_node.processed_chunk = select_chunks_upto+select_chunks_with_retry obj_source_node.node_count = node_count - obj_source_node.processed_chunk = select_chunks_upto obj_source_node.relationship_count = rel_count graphDb_data_Access.update_source_node(obj_source_node) @@ -406,6 +416,47 @@ def processing_chunks(chunkId_chunkDoc_list,graph,uri, userName, password, datab print(f'relation count internal func:{rel_count}') return node_count,rel_count +def get_chunkId_chunkDoc_list(graph, file_name, pages, retry_condition): + if retry_condition is None: + logging.info("Break down file into chunks") + bad_chars = ['"', "\n", "'"] + for i in range(0,len(pages)): + text = pages[i].page_content + for j in bad_chars: + if j == '\n': + text = text.replace(j, ' ') + else: + text = text.replace(j, '') + pages[i]=Document(page_content=str(text), metadata=pages[i].metadata) + create_chunks_obj = CreateChunksofDocument(pages, graph) + chunks = create_chunks_obj.split_file_into_chunks() + chunkId_chunkDoc_list = create_relation_between_chunks(graph,file_name,chunks) + return len(chunks), chunkId_chunkDoc_list + + else: + chunkId_chunkDoc_list=[] + chunks = graph.query(QUERY_TO_GET_CHUNKS, params={"filename":file_name}) + for chunk in chunks: + chunk_doc = Document(page_content=chunk['text'], metadata={'id':chunk['id'], 'position':chunk['position']}) + chunkId_chunkDoc_list.append({'chunk_id': chunk['id'], 'chunk_doc': chunk_doc}) + + if retry_condition == START_FROM_LAST_PROCESSED_POSITION: + logging.info(f"Retry : start_from_last_processed_position") + starting_chunk = graph.query(QUERY_TO_GET_LAST_PROCESSED_CHUNK_POSITION, params={"filename":file_name}) + if starting_chunk[0]["position"] < len(chunkId_chunkDoc_list): + return len(chunks), chunkId_chunkDoc_list[starting_chunk[0]["position"] - 1:] + + elif starting_chunk[0]["position"] == len(chunkId_chunkDoc_list): + starting_chunk = graph.query(QUERY_TO_GET_LAST_PROCESSED_CHUNK_WITHOUT_ENTITY, params={"filename":file_name}) + return len(chunks), chunkId_chunkDoc_list[starting_chunk[0]["position"] - 1:] + + else: + raise Exception(f"All chunks of {file_name} are alreday processed. If you want to re-process, Please start from begnning") + + else: + logging.info(f"Retry : start_from_beginning with chunks {len(chunkId_chunkDoc_list)}") + return len(chunks), chunkId_chunkDoc_list + def get_source_list_from_graph(uri,userName,password,db_name=None): """ Args: @@ -561,4 +612,21 @@ def populate_graph_schema_from_text(text, model, is_schema_description_cheked): data (list): list of lebels and relationTypes """ result = schema_extraction_from_text(text, model, is_schema_description_cheked) - return {"labels": result.labels, "relationshipTypes": result.relationshipTypes} \ No newline at end of file + return {"labels": result.labels, "relationshipTypes": result.relationshipTypes} + +def set_status_retry(graph, file_name, retry_condition): + graphDb_data_Access = graphDBdataAccess(graph) + obj_source_node = sourceNode() + status = "Reprocess" + obj_source_node.file_name = file_name + obj_source_node.status = status + obj_source_node.retry_condition = retry_condition + obj_source_node.is_cancelled = False + if retry_condition == DELETE_ENTITIES_AND_START_FROM_BEGINNING or retry_condition == START_FROM_BEGINNING: + obj_source_node.processed_chunk=0 + if retry_condition == DELETE_ENTITIES_AND_START_FROM_BEGINNING: + graph.query(QUERY_TO_DELETE_EXISTING_ENTITIES, params={"filename":file_name}) + obj_source_node.node_count=0 + obj_source_node.relationship_count=0 + logging.info(obj_source_node) + graphDb_data_Access.update_source_node(obj_source_node) \ No newline at end of file diff --git a/backend/src/shared/constants.py b/backend/src/shared/constants.py index b67e92730..8bb1c56b1 100644 --- a/backend/src/shared/constants.py +++ b/backend/src/shared/constants.py @@ -277,3 +277,42 @@ RETURN text, avg_score as score, {{length:size(text), source: COALESCE( CASE WHEN d.url CONTAINS "None" THEN d.fileName ELSE d.url END, d.fileName), chunkdetails: chunkdetails}} AS metadata """ YOUTUBE_CHUNK_SIZE_SECONDS = 60 + +QUERY_TO_GET_CHUNKS = """ + MATCH (d:Document) + WHERE d.fileName = $filename + WITH d + OPTIONAL MATCH (d)<-[:PART_OF|FIRST_CHUNK]-(c:Chunk) + RETURN c.id as id, c.text as text, c.position as position + """ + +QUERY_TO_DELETE_EXISTING_ENTITIES = """ + MATCH (d:Document {fileName:$filename}) + WITH d + MATCH (d)<-[:PART_OF]-(c:Chunk) + WITH d,c + MATCH (c)-[:HAS_ENTITY]->(e) + WHERE NOT EXISTS { (e)<-[:HAS_ENTITY]-()<-[:PART_OF]-(d2:Document) } + DETACH DELETE e + """ + +QUERY_TO_GET_LAST_PROCESSED_CHUNK_POSITION=""" + MATCH (d:Document) + WHERE d.fileName = $filename + WITH d + MATCH (c:Chunk) WHERE c.embedding is null + RETURN c.id as id,c.position as position + ORDER BY c.position LIMIT 1 + """ +QUERY_TO_GET_LAST_PROCESSED_CHUNK_WITHOUT_ENTITY = """ + MATCH (d:Document) + WHERE d.fileName = $filename + WITH d + MATCH (d)<-[:PART_OF]-(c:Chunk) WHERE NOT exists {(c)-[:HAS_ENTITY]->()} + RETURN c.id as id,c.position as position + ORDER BY c.position LIMIT 1 + """ + +START_FROM_BEGINNING = "start_from_beginning" +DELETE_ENTITIES_AND_START_FROM_BEGINNING = "delete_entities_and_start_from_beginning" +START_FROM_LAST_PROCESSED_POSITION = "start_from_last_processed_position" diff --git a/frontend/example.env b/frontend/example.env index 63bd3e7c3..9bc5bc0d5 100644 --- a/frontend/example.env +++ b/frontend/example.env @@ -8,4 +8,4 @@ VITE_CHUNK_SIZE=5242880 VITE_LARGE_FILE_SIZE=5242880 VITE_GOOGLE_CLIENT_ID="" VITE_CHAT_MODES="" -VITE_BATCH_SIZE=2 \ No newline at end of file +VITE_BATCH_SIZE=2 diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index f35599b98..df97d4c09 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -5,7 +5,7 @@ import QuickStarter from './components/QuickStarter'; import { GoogleOAuthProvider } from '@react-oauth/google'; import { APP_SOURCES } from './utils/Constants'; import ErrorBoundary from './components/UI/ErrroBoundary'; - +import { Toaster } from '@neo4j-ndl/react'; const App: React.FC = () => { return ( <> @@ -14,6 +14,7 @@ const App: React.FC = () => { + @@ -21,6 +22,7 @@ const App: React.FC = () => { + )} diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index 89c15ea72..3c6642665 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -131,11 +131,12 @@ const ChatInfoModal: React.FC = ({ }; const labelCounts = useMemo(() => { const counts: { [label: string]: number } = {}; - infoEntities.forEach((entity) => { + for (let index = 0; index < infoEntities.length; index++) { + const entity = infoEntities[index]; const { labels } = entity; const [label] = labels; counts[label] = counts[label] ? counts[label] + 1 : 1; - }); + } return counts; }, [infoEntities]); const sortedLabels = useMemo(() => { diff --git a/frontend/src/components/ChatBot/Chatbot.tsx b/frontend/src/components/ChatBot/Chatbot.tsx index 448af0e7d..7352b0ff4 100644 --- a/frontend/src/components/ChatBot/Chatbot.tsx +++ b/frontend/src/components/ChatBot/Chatbot.tsx @@ -55,13 +55,15 @@ const Chatbot: FC = (props) => { }, }); let selectedFileNames: CustomFile[] = []; - selectedRows.forEach((id) => { - filesData.forEach((f) => { + for (let index = 0; index < selectedRows.length; index++) { + const id = selectedRows[index]; + for (let index = 0; index < filesData.length; index++) { + const f = filesData[index]; if (f.id === id) { selectedFileNames.push(f); } - }); - }); + } + } const handleInputChange = (e: React.ChangeEvent) => { setInputMessage(e.target.value); diff --git a/frontend/src/components/ChatBot/Info/InfoModal.tsx b/frontend/src/components/ChatBot/Info/InfoModal.tsx index cf1bbca47..0d5b82a64 100644 --- a/frontend/src/components/ChatBot/Info/InfoModal.tsx +++ b/frontend/src/components/ChatBot/Info/InfoModal.tsx @@ -77,11 +77,12 @@ const InfoModal: React.FC = ({ sources, model, total_tokens, re }; const labelCounts = useMemo(() => { const counts: { [label: string]: number } = {}; - infoEntities.forEach((entity) => { + for (let index = 0; index < infoEntities.length; index++) { + const entity = infoEntities[index]; const { labels } = entity; const [label] = labels; counts[label] = counts[label] ? counts[label] + 1 : 1; - }); + } return counts; }, [infoEntities]); const sortedLabels = useMemo(() => { diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 44e7fd325..877c1178b 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -1,17 +1,16 @@ -import { useEffect, useState, useMemo, useRef, Suspense } from 'react'; +import { useEffect, useState, useMemo, useRef, Suspense, useReducer, useCallback } from 'react'; import FileTable from './FileTable'; import { Button, Typography, Flex, StatusIndicator, useMediaQuery } from '@neo4j-ndl/react'; import { useCredentials } from '../context/UserCredentials'; import { useFileContext } from '../context/UsersFiles'; -import CustomAlert from './UI/Alert'; import { extractAPI } from '../utils/FileAPI'; import { + BannerAlertProps, ChildRef, ContentProps, CustomFile, OptionType, UserCredentials, - alertStateType, connectionState, } from '../types'; import deleteAPI from '../services/DeleteFiles'; @@ -19,22 +18,24 @@ import { postProcessing } from '../services/PostProcessing'; import { triggerStatusUpdateAPI } from '../services/ServerSideStatusUpdateAPI'; import useServerSideEvent from '../hooks/useSse'; import { useSearchParams } from 'react-router-dom'; -import { batchSize, buttonCaptions, defaultLLM, largeFileSize, llms, tooltips } from '../utils/Constants'; +import { batchSize, buttonCaptions, defaultLLM, largeFileSize, llms, RETRY_OPIONS, tooltips } from '../utils/Constants'; import ButtonWithToolTip from './UI/ButtonWithToolTip'; import connectAPI from '../services/ConnectAPI'; import DropdownComponent from './Dropdown'; import GraphViewModal from './Graph/GraphViewModal'; -import { OverridableStringUnion } from '@mui/types'; -import { AlertColor, AlertPropsColorOverrides } from '@mui/material'; import { lazy } from 'react'; import FallBackDialog from './UI/FallBackDialog'; import DeletePopUp from './Popups/DeletePopUp/DeletePopUp'; import GraphEnhancementDialog from './Popups/GraphEnhancementDialog'; import { tokens } from '@neo4j-ndl/base'; +import RetryConfirmationDialog from './Popups/RetryConfirmation/Index'; +import retry from '../services/retry'; +import { showErrorToast, showNormalToast, showSuccessToast } from '../utils/toasts'; import axios from 'axios'; const ConnectionModal = lazy(() => import('./Popups/ConnectionModal/ConnectionModal')); const ConfirmationDialog = lazy(() => import('./Popups/LargeFilePopUp/ConfirmationDialog')); + let afterFirstRender = false; const Content: React.FC = ({ @@ -60,6 +61,14 @@ const Content: React.FC = ({ const { setUserCredentials, userCredentials, connectionStatus, setConnectionStatus } = useCredentials(); const [showConfirmationModal, setshowConfirmationModal] = useState(false); const [extractLoading, setextractLoading] = useState(false); + const [retryFile, setRetryFile] = useState(''); + const [retryLoading, setRetryLoading] = useState(false); + const [showRetryPopup, toggleRetryPopup] = useReducer((state) => !state, false); + const [alertStateForRetry, setAlertStateForRetry] = useState({ + showAlert: false, + alertType: 'neutral', + alertMessage: '', + }); const { filesData, @@ -80,39 +89,18 @@ const Content: React.FC = ({ const [showDeletePopUp, setshowDeletePopUp] = useState(false); const [deleteLoading, setdeleteLoading] = useState(false); const [searchParams] = useSearchParams(); - const [alertDetails, setalertDetails] = useState({ - showAlert: false, - alertType: 'error', - alertMessage: '', - }); + const { updateStatusForLargeFiles } = useServerSideEvent( (inMinutes, time, fileName) => { - setalertDetails({ - showAlert: true, - alertType: 'info', - alertMessage: `${fileName} will take approx ${time} ${inMinutes ? 'Min' : 'Sec'}`, - }); + showNormalToast(`${fileName} will take approx ${time} ${inMinutes ? 'Min' : 'Sec'}`); localStorage.setItem('alertShown', JSON.stringify(true)); }, (fileName) => { - setalertDetails({ - showAlert: true, - alertType: 'error', - alertMessage: `${fileName} Failed to process`, - }); + showErrorToast(`${fileName} Failed to process`); } ); const childRef = useRef(null); - const showAlert = ( - alertmsg: string, - alerttype: OverridableStringUnion | undefined - ) => { - setalertDetails({ - showAlert: true, - alertMessage: alertmsg, - alertType: alerttype, - }); - }; + useEffect(() => { if (!init && !searchParams.has('connectURL')) { let session = localStorage.getItem('neo4j.connection'); @@ -158,6 +146,57 @@ const Content: React.FC = ({ afterFirstRender = true; }, [queue.items.length, userCredentials]); + useEffect(() => { + const storedSchema = localStorage.getItem('isSchema'); + if (storedSchema !== null) { + setIsSchema(JSON.parse(storedSchema)); + } + }, [isSchema]); + + useEffect(() => { + const connection = localStorage.getItem('neo4j.connection'); + if (connection != null) { + (async () => { + const parsedData = JSON.parse(connection); + console.log(parsedData.uri); + const response = await connectAPI(parsedData.uri, parsedData.user, parsedData.password, parsedData.database); + if (response?.data?.status === 'Success') { + localStorage.setItem( + 'neo4j.connection', + JSON.stringify({ + ...parsedData, + userDbVectorIndex: response.data.data.db_vector_dimension, + }) + ); + if ( + (response.data.data.application_dimension === response.data.data.db_vector_dimension || + response.data.data.db_vector_dimension == 0) && + !response.data.data.chunks_exists + ) { + setConnectionStatus(true); + setOpenConnection((prev) => ({ ...prev, openPopUp: false })); + } else { + setOpenConnection({ + openPopUp: true, + chunksExists: response.data.data.chunks_exists as boolean, + vectorIndexMisMatch: + response.data.data.db_vector_dimension > 0 && + response.data.data.db_vector_dimension != response.data.data.application_dimension, + chunksExistsWithDifferentDimension: + response.data.data.db_vector_dimension > 0 && + response.data.data.db_vector_dimension != response.data.data.application_dimension && + (response.data.data.chunks_exists ?? true), + }); + setConnectionStatus(false); + } + } else { + setOpenConnection((prev) => ({ ...prev, openPopUp: true })); + setConnectionStatus(false); + } + })(); + } + }, []); + const handleDropdownChange = (selectedOption: OptionType | null | void) => { if (selectedOption?.value) { setModel(selectedOption?.value); @@ -219,6 +258,7 @@ const Content: React.FC = ({ fileItem.model, userCredentials as UserCredentials, fileItem.fileSource, + fileItem.retryOption ?? '', fileItem.source_url, localStorage.getItem('accesskey'), localStorage.getItem('secretkey'), @@ -267,11 +307,7 @@ const Content: React.FC = ({ const { message, fileName } = error; queue.remove(fileName); const errorMessage = error.message; - setalertDetails({ - showAlert: true, - alertType: 'error', - alertMessage: message, - }); + showErrorToast(message); setFilesData((prevfiles) => prevfiles.map((curfile) => { if (curfile.name == fileName) { @@ -304,14 +340,10 @@ const Content: React.FC = ({ newCheck: boolean ) => { const data = []; - setalertDetails({ - showAlert: true, - alertMessage: `Processing ${batch.length} files at a time.`, - alertType: 'info', - }); + showNormalToast(`Processing ${batch.length} files at a time.`); for (let i = 0; i < batch.length; i++) { if (newCheck) { - if (batch[i]?.status === 'New') { + if (batch[i]?.status === 'New' || batch[i].status === 'Reprocess') { data.push(extractData(batch[i].id, isSelectedFiles, selectedFiles as CustomFile[])); } } else { @@ -322,7 +354,8 @@ const Content: React.FC = ({ }; const addFilesToQueue = (remainingFiles: CustomFile[]) => { - remainingFiles.forEach((f) => { + for (let index = 0; index < remainingFiles.length; index++) { + const f = remainingFiles[index]; setFilesData((prev) => prev.map((pf) => { if (pf.id === f.id) { @@ -335,7 +368,7 @@ const Content: React.FC = ({ }) ); queue.enqueue(f); - }); + } }; const scheduleBatchWiseProcess = (selectedRows: CustomFile[], isSelectedFiles: boolean) => { @@ -427,13 +460,12 @@ const Content: React.FC = ({ await postProcessing(userCredentials as UserCredentials, postProcessingTasks); }); } else { - const selectedNewFiles = childRef.current?.getSelectedRows().filter((f) => f.status === 'New'); + const selectedNewFiles = childRef.current + ?.getSelectedRows() + .filter((f) => f.status === 'New' || f.status == 'Reprocess'); addFilesToQueue(selectedNewFiles as CustomFile[]); } } - const handleClose = () => { - setalertDetails((prev) => ({ ...prev, showAlert: false, alertMessage: '' })); - }; const handleOpenGraphClick = () => { const bloomUrl = process.env.VITE_BLOOM_URL; @@ -470,13 +502,48 @@ const Content: React.FC = ({ setSelectedRels([]); }; + const retryHandler = async (filename: string, retryoption: string) => { + try { + setRetryLoading(true); + const response = await retry(userCredentials as UserCredentials, filename, retryoption); + setRetryLoading(false); + if (response.data.status === 'Failure') { + throw new Error(response.data.error); + } + setFilesData((prev) => { + return prev.map((f) => { + return f.name === filename + ? { + ...f, + status: 'Reprocess', + processingProgress: retryoption.includes('start_from_beginning') ? 0 : f.processingProgress, + NodesCount: retryoption === RETRY_OPIONS[1] ? 0 : f.NodesCount, + relationshipCount: retryoption === RETRY_OPIONS[1] ? 0 : f.relationshipCount, + } + : f; + }); + }); + showSuccessToast(response.data.message as string); + retryOnclose(); + } catch (error) { + setRetryLoading(false); + if (error instanceof Error) { + setAlertStateForRetry({ + showAlert: true, + alertMessage: error.message, + alertType: 'danger', + }); + } + } + }; + const selectedfileslength = useMemo( () => childRef.current?.getSelectedRows().length, [childRef.current?.getSelectedRows()] ); const newFilecheck = useMemo( - () => childRef.current?.getSelectedRows().filter((f) => f.status === 'New').length, + () => childRef.current?.getSelectedRows().filter((f) => f.status === 'New' || f.status == 'Reprocess').length, [childRef.current?.getSelectedRows()] ); @@ -486,7 +553,7 @@ const Content: React.FC = ({ ); const dropdowncheck = useMemo( - () => !filesData.some((f) => f.status === 'New' || f.status === 'Waiting'), + () => !filesData.some((f) => f.status === 'New' || f.status === 'Waiting' || f.status === 'Reprocess'), [filesData] ); @@ -502,15 +569,16 @@ const Content: React.FC = ({ const filesForProcessing = useMemo(() => { let newstatusfiles: CustomFile[] = []; - if (childRef.current?.getSelectedRows().length) { - childRef.current?.getSelectedRows().forEach((f) => { - const parsedFile: CustomFile = f; - if (parsedFile.status === 'New') { + const selectedRows = childRef.current?.getSelectedRows(); + if (selectedRows?.length) { + for (let index = 0; index < selectedRows.length; index++) { + const parsedFile: CustomFile = selectedRows[index]; + if (parsedFile.status === 'New' || parsedFile.status == 'Reprocess') { newstatusfiles.push(parsedFile); } - }); + } } else if (filesData.length) { - newstatusfiles = filesData.filter((f) => f.status === 'New'); + newstatusfiles = filesData.filter((f) => f.status === 'New' || f.status === 'Reprocess'); } return newstatusfiles; }, [filesData, childRef.current?.getSelectedRows()]); @@ -528,15 +596,14 @@ const Content: React.FC = ({ setRowSelection({}); setdeleteLoading(false); if (response.data.status == 'Success') { - setalertDetails({ - showAlert: true, - alertMessage: response.data.message, - alertType: 'success', - }); + showSuccessToast(response.data.message); const filenames = childRef.current?.getSelectedRows().map((str) => str.name); - filenames?.forEach((name) => { - setFilesData((prev) => prev.filter((f) => f.name != name)); - }); + if (filenames?.length) { + for (let index = 0; index < filenames.length; index++) { + const name = filenames[index]; + setFilesData((prev) => prev.filter((f) => f.name != name)); + } + } } else { let errorobj = { error: response.data.error, message: response.data.message }; throw new Error(JSON.stringify(errorobj)); @@ -547,94 +614,41 @@ const Content: React.FC = ({ if (err instanceof Error) { const error = JSON.parse(err.message); const { message } = error; - setalertDetails({ - showAlert: true, - alertType: 'error', - alertMessage: message, - }); + showErrorToast(message); console.log(err); } } setshowDeletePopUp(false); }; - useEffect(() => { - const connection = localStorage.getItem('neo4j.connection'); - if (connection != null) { - (async () => { - const parsedData = JSON.parse(connection); - console.log(parsedData.uri); - const response = await connectAPI(parsedData.uri, parsedData.user, parsedData.password, parsedData.database); - if (response?.data?.status === 'Success') { - localStorage.setItem( - 'neo4j.connection', - JSON.stringify({ - ...parsedData, - userDbVectorIndex: response.data.data.db_vector_dimension, - }) - ); - if ( - (response.data.data.application_dimension === response.data.data.db_vector_dimension || - response.data.data.db_vector_dimension == 0) && - !response.data.data.chunks_exists - ) { - setConnectionStatus(true); - setOpenConnection((prev) => ({ ...prev, openPopUp: false })); - } else { - setOpenConnection({ - openPopUp: true, - chunksExists: response.data.data.chunks_exists as boolean, - vectorIndexMisMatch: - response.data.data.db_vector_dimension > 0 && - response.data.data.db_vector_dimension != response.data.data.application_dimension, - chunksExistsWithDifferentDimension: - response.data.data.db_vector_dimension > 0 && - response.data.data.db_vector_dimension != response.data.data.application_dimension && - (response.data.data.chunks_exists ?? true), - }); - setConnectionStatus(false); - } - } else { - setOpenConnection((prev) => ({ ...prev, openPopUp: true })); - setConnectionStatus(false); - } - })(); - } - }, []); - - useEffect(() => { - const storedSchema = localStorage.getItem('isSchema'); - if (storedSchema !== null) { - setIsSchema(JSON.parse(storedSchema)); - } - }, [isSchema]); const onClickHandler = () => { - if (childRef.current?.getSelectedRows().length) { + const selectedRows = childRef.current?.getSelectedRows(); + if (selectedRows?.length) { let selectedLargeFiles: CustomFile[] = []; - childRef.current?.getSelectedRows().forEach((f) => { - const parsedData: CustomFile = f; + for (let index = 0; index < selectedRows.length; index++) { + const parsedData: CustomFile = selectedRows[index]; if ( parsedData.fileSource === 'local file' && typeof parsedData.size === 'number' && - parsedData.status === 'New' && + (parsedData.status === 'New' || parsedData.status == 'Reprocess') && parsedData.size > largeFileSize ) { selectedLargeFiles.push(parsedData); } - }); + } if (selectedLargeFiles.length) { setshowConfirmationModal(true); } else { - handleGenerateGraph(childRef.current?.getSelectedRows().filter((f) => f.status === 'New')); + handleGenerateGraph(selectedRows.filter((f) => f.status === 'New' || f.status === 'Reprocess')); } } else if (filesData.length) { const largefiles = filesData.filter((f) => { - if (typeof f.size === 'number' && f.status === 'New' && f.size > largeFileSize) { + if (typeof f.size === 'number' && (f.status === 'New' || f.status == 'Reprocess') && f.size > largeFileSize) { return true; } return false; }); - const selectAllNewFiles = filesData.filter((f) => f.status === 'New'); + const selectAllNewFiles = filesData.filter((f) => f.status === 'New' || f.status === 'Reprocess'); const stringified = selectAllNewFiles.reduce((accu, f) => { const key = f.id; // @ts-ignore @@ -645,29 +659,41 @@ const Content: React.FC = ({ if (largefiles.length) { setshowConfirmationModal(true); } else { - handleGenerateGraph(filesData.filter((f) => f.status === 'New')); + handleGenerateGraph(filesData.filter((f) => f.status === 'New' || f.status === 'Reprocess')); } } }; + const retryOnclose = useCallback(() => { + setRetryFile(''); + setAlertStateForRetry({ + showAlert: false, + alertMessage: '', + alertType: 'neutral', + }); + setRetryLoading(false); + toggleRetryPopup(); + }, []); + + const onBannerClose = useCallback(() => { + setAlertStateForRetry({ + showAlert: false, + alertMessage: '', + alertType: 'neutral', + }); + }, []); + return ( <> - {alertDetails.showAlert && ( - - )} - {isSchema && ( - - )} + {showConfirmationModal && filesForProcessing.length && ( }> = ({ open={showEnhancementDialog} onClose={toggleEnhancementDialog} closeSettingModal={closeSettingModal} - showAlert={showAlert} > )}
@@ -777,6 +802,10 @@ const Content: React.FC = ({ setOpenGraphView(true); setViewPoint('tableView'); }} + onRetry={(id) => { + setRetryFile(id); + toggleRetryPopup(); + }} ref={childRef} handleGenerateGraph={processWaitingFilesOnRefresh} > diff --git a/frontend/src/components/DataSources/AWS/S3Modal.tsx b/frontend/src/components/DataSources/AWS/S3Modal.tsx index 2f40c9709..221fb0c9c 100644 --- a/frontend/src/components/DataSources/AWS/S3Modal.tsx +++ b/frontend/src/components/DataSources/AWS/S3Modal.tsx @@ -38,6 +38,8 @@ const S3Modal: React.FC = ({ hideModal, open }) => { model: model, fileSource: 's3 bucket', processingProgress: undefined, + retryOption: '', + retryOptionStatus: false, }; if (url) { setValid(validation(bucketUrl) && isFocused); @@ -123,7 +125,19 @@ const S3Modal: React.FC = ({ hideModal, open }) => { reset(); setStatus('unknown'); }; - + const handleKeyDown: React.KeyboardEventHandler = (e) => { + if (e.code === 'Enter') { + e.preventDefault(); // + // @ts-ignore + const { form } = e.target; + const index = Array.prototype.indexOf.call(form, e.target); + if (index + 1 < form.elements.length) { + form.elements[index + 1].focus(); + } else { + submitHandler(bucketUrl); + } + } + }; return ( = ({ hideModal, open }) => { submitLabel={buttonCaptions.submit} >
- setValid(validation(bucketUrl) && isFocused)} - onChange={(e) => { - setisFocused(true); - setBucketUrl(e.target.value); - }} - /> -
-
- { - setAccessKey(e.target.value); - }} - /> - { - setSecretKey(e.target.value); - }} - /> +
+ setValid(validation(bucketUrl) && isFocused)} + onChange={(e) => { + setisFocused(true); + setBucketUrl(e.target.value); + }} + onKeyDown={handleKeyDown} + /> +
+ { + setAccessKey(e.target.value); + }} + onKeyDown={handleKeyDown} + /> + { + setSecretKey(e.target.value); + }} + onKeyDown={handleKeyDown} + /> +
+
); diff --git a/frontend/src/components/DataSources/GCS/GCSModal.tsx b/frontend/src/components/DataSources/GCS/GCSModal.tsx index a4cd3d8f9..007ffab2b 100644 --- a/frontend/src/components/DataSources/GCS/GCSModal.tsx +++ b/frontend/src/components/DataSources/GCS/GCSModal.tsx @@ -9,6 +9,7 @@ import CustomModal from '../../../HOC/CustomModal'; import { useGoogleLogin } from '@react-oauth/google'; import { useAlertContext } from '../../../context/Alert'; import { buttonCaptions } from '../../../utils/Constants'; +import { showErrorToast, showNormalToast } from '../../../utils/toasts'; const GCSModal: React.FC = ({ hideModal, open, openGCSModal }) => { const [bucketName, setbucketName] = useState(''); @@ -30,6 +31,8 @@ const GCSModal: React.FC = ({ hideModal, open, openGCSModal }) => model: model, fileSource: 'gcs bucket', processingProgress: undefined, + retryOption: '', + retryOptionStatus: false, }; const reset = () => { @@ -67,7 +70,7 @@ const GCSModal: React.FC = ({ hideModal, open, openGCSModal }) => access_token: codeResponse.access_token, }); if (apiResponse.data.status == 'Failed' || !apiResponse.data) { - showAlert('error', apiResponse?.data?.message); + showErrorToast(apiResponse?.data?.message); setTimeout(() => { setStatus('unknown'); reset(); @@ -77,52 +80,54 @@ const GCSModal: React.FC = ({ hideModal, open, openGCSModal }) => } const apiResCheck = apiResponse?.data?.success_count && apiResponse.data.failed_count; if (apiResCheck) { - showAlert( - 'info', + showNormalToast( `Successfully Created Source Nodes for ${apiResponse.data.success_count} and Failed for ${apiResponse.data.failed_count} Files` ); } else if (apiResponse?.data?.success_count) { - showAlert('info', `Successfully Created Source Nodes for ${apiResponse.data.success_count} Files`); + showNormalToast(`Successfully Created Source Nodes for ${apiResponse.data.success_count} Files`); } else if (apiResponse.data.failed_count) { - showAlert('error', `Failed to Created Source Node for ${apiResponse.data.failed_count} Files`); + showErrorToast(`Failed to Created Source Node for ${apiResponse.data.failed_count} Files`); } else { - showAlert('error', `Invalid Folder Name`); + showErrorToast(`Invalid Folder Name`); } const copiedFilesData = [...filesData]; - apiResponse?.data?.file_name?.forEach((item: fileName) => { - const filedataIndex = copiedFilesData.findIndex((filedataitem) => filedataitem?.name === item.fileName); - if (filedataIndex == -1) { - copiedFilesData.unshift({ - name: item.fileName, - size: item.fileSize ?? 0, - gcsBucket: item.gcsBucketName, - gcsBucketFolder: item.gcsBucketFolder, - google_project_id: item.gcsProjectId, - id: uuidv4(), - access_token: codeResponse.access_token, - ...defaultValues, - }); - } else { - const tempFileData = copiedFilesData[filedataIndex]; - copiedFilesData.splice(filedataIndex, 1); - copiedFilesData.unshift({ - ...tempFileData, - status: defaultValues.status, - NodesCount: defaultValues.NodesCount, - relationshipCount: defaultValues.relationshipCount, - processing: defaultValues.processing, - model: defaultValues.model, - fileSource: defaultValues.fileSource, - processingProgress: defaultValues.processingProgress, - access_token: codeResponse.access_token, - }); + if (apiResponse?.data?.file_name?.length) { + for (let index = 0; index < apiResponse?.data?.file_name.length; index++) { + const item: fileName = apiResponse?.data?.file_name[index]; + const filedataIndex = copiedFilesData.findIndex((filedataitem) => filedataitem?.name === item.fileName); + if (filedataIndex == -1) { + copiedFilesData.unshift({ + name: item.fileName, + size: item.fileSize ?? 0, + gcsBucket: item.gcsBucketName, + gcsBucketFolder: item.gcsBucketFolder, + google_project_id: item.gcsProjectId, + id: uuidv4(), + access_token: codeResponse.access_token, + ...defaultValues, + }); + } else { + const tempFileData = copiedFilesData[filedataIndex]; + copiedFilesData.splice(filedataIndex, 1); + copiedFilesData.unshift({ + ...tempFileData, + status: defaultValues.status, + NodesCount: defaultValues.NodesCount, + relationshipCount: defaultValues.relationshipCount, + processing: defaultValues.processing, + model: defaultValues.model, + fileSource: defaultValues.fileSource, + processingProgress: defaultValues.processingProgress, + access_token: codeResponse.access_token, + }); + } } - }); + } setFilesData(copiedFilesData); reset(); } catch (error) { if (showAlert != undefined) { - showAlert('error', 'Some Error Occurred or Please Check your Instance Connection'); + showNormalToast('Some Error Occurred or Please Check your Instance Connection'); } } setTimeout(() => { @@ -131,15 +136,14 @@ const GCSModal: React.FC = ({ hideModal, open, openGCSModal }) => }, 500); }, onError: (errorResponse) => { - showAlert( - 'error', + showErrorToast( errorResponse.error_description ?? 'Some Error Occurred or Please try signin with your google account' ); }, scope: 'https://www.googleapis.com/auth/devstorage.read_only', onNonOAuthError: (error: nonoautherror) => { console.log(error); - showAlert('info', error.message as string); + showNormalToast(error.message as string); }, }); @@ -163,6 +167,19 @@ const GCSModal: React.FC = ({ hideModal, open, openGCSModal }) => reset(); setStatus('unknown'); }, []); + const handleKeyPress: React.KeyboardEventHandler = (e) => { + if (e.code === 'Enter') { + e.preventDefault(); // + // @ts-ignore + const { form } = e.target; + const index = Array.prototype.indexOf.call(form, e.target); + if (index + 1 < form.elements.length) { + form.elements[index + 1].focus(); + } else { + submitHandler(); + } + } + }; return ( = ({ hideModal, open, openGCSModal }) => submitLabel={buttonCaptions.submit} >
- { - setprojectId(e.target.value); - }} - > - { - setbucketName(e.target.value); - }} - /> - { - setFolderName(e.target.value); - }} - /> +
+ { + setprojectId(e.target.value); + }} + onKeyDown={handleKeyPress} + > + { + setbucketName(e.target.value); + }} + onKeyDown={handleKeyPress} + /> + { + setFolderName(e.target.value); + }} + onKeyDown={handleKeyPress} + /> +
); diff --git a/frontend/src/components/DataSources/Local/DropZone.tsx b/frontend/src/components/DataSources/Local/DropZone.tsx index 63ff08e37..7ff5d90d2 100644 --- a/frontend/src/components/DataSources/Local/DropZone.tsx +++ b/frontend/src/components/DataSources/Local/DropZone.tsx @@ -1,26 +1,21 @@ import { Dropzone, Flex, Typography } from '@neo4j-ndl/react'; -import React, { useState, useEffect, FunctionComponent } from 'react'; +import { useState, useEffect, FunctionComponent } from 'react'; import Loader from '../../../utils/Loader'; import { v4 as uuidv4 } from 'uuid'; import { useCredentials } from '../../../context/UserCredentials'; import { useFileContext } from '../../../context/UsersFiles'; -import CustomAlert from '../../UI/Alert'; -import { CustomFile, CustomFileBase, UserCredentials, alertStateType } from '../../../types'; +import { CustomFile, CustomFileBase, UserCredentials } from '../../../types'; import { buttonCaptions, chunkSize } from '../../../utils/Constants'; import { InformationCircleIconOutline } from '@neo4j-ndl/react/icons'; import IconButtonWithToolTip from '../../UI/IconButtonToolTip'; import { uploadAPI } from '../../../utils/FileAPI'; +import { showErrorToast, showSuccessToast } from '../../../utils/toasts'; const DropZone: FunctionComponent = () => { const { filesData, setFilesData, model } = useFileContext(); const [isLoading, setIsLoading] = useState(false); const [isClicked, setIsClicked] = useState(false); const { userCredentials } = useCredentials(); - const [alertDetails, setalertDetails] = React.useState({ - showAlert: false, - alertType: 'error', - alertMessage: '', - }); const [selectedFiles, setSelectedFiles] = useState([]); const onDropHandler = (f: Partial[]) => { @@ -37,11 +32,13 @@ const DropZone: FunctionComponent = () => { fileSource: 'local file', uploadprogess: 0, processingProgress: undefined, + retryOptionStatus: false, + retryOption: '', }; const copiedFilesData: CustomFile[] = [...filesData]; - - f.forEach((file) => { + for (let index = 0; index < f.length; index++) { + const file = f[index]; const filedataIndex = copiedFilesData.findIndex((filedataitem) => filedataitem?.name === file?.name); if (filedataIndex == -1) { copiedFilesData.unshift({ @@ -67,22 +64,19 @@ const DropZone: FunctionComponent = () => { processingProgress: defaultValues.processingProgress, }); } - }); + } setFilesData(copiedFilesData); } }; - const handleClose = () => { - setalertDetails((prev) => ({ ...prev, showAlert: false, alertMessage: '' })); - }; - useEffect(() => { if (selectedFiles.length > 0) { - selectedFiles.forEach((file, uid) => { - if (filesData[uid]?.status == 'None' && isClicked) { + for (let index = 0; index < selectedFiles.length; index++) { + const file = selectedFiles[index]; + if (filesData[index]?.status == 'None' && isClicked) { uploadFileInChunks(file); } - }); + } } }, [selectedFiles]); const uploadFileInChunks = (file: File) => { @@ -162,17 +156,15 @@ const DropZone: FunctionComponent = () => { } } catch (error) { setIsLoading(false); - setalertDetails({ - showAlert: true, - alertType: 'error', - alertMessage: 'Error Occurred', - }); + if (error instanceof Error) { + showErrorToast(`Error Occurred: ${error.message}`, true); + } setFilesData((prevfiles) => prevfiles.map((curfile) => { if (curfile.name == file.name) { return { ...curfile, - status: 'Failed', + status: 'Upload Failed', type: `${file.name.substring(file.name.lastIndexOf('.') + 1, file.name.length).toUpperCase()}`, }; } @@ -195,11 +187,7 @@ const DropZone: FunctionComponent = () => { ); setIsClicked(false); setIsLoading(false); - setalertDetails({ - showAlert: true, - alertType: 'success', - alertMessage: `${file.name} uploaded successfully`, - }); + showSuccessToast(`${file.name} uploaded successfully`); } }; @@ -208,15 +196,6 @@ const DropZone: FunctionComponent = () => { return ( <> - {alertDetails.showAlert && ( - - )} - } isTesting={true} @@ -262,11 +241,7 @@ const DropZone: FunctionComponent = () => { }, onDropRejected: (e) => { if (e.length) { - setalertDetails({ - showAlert: true, - alertType: 'error', - alertMessage: 'Failed To Upload, Unsupported file extention', - }); + showErrorToast('Failed To Upload, Unsupported file extention'); } }, }} diff --git a/frontend/src/components/DataSources/Local/DropZoneForSmallLayouts.tsx b/frontend/src/components/DataSources/Local/DropZoneForSmallLayouts.tsx index 06a16b639..21bd47240 100644 --- a/frontend/src/components/DataSources/Local/DropZoneForSmallLayouts.tsx +++ b/frontend/src/components/DataSources/Local/DropZoneForSmallLayouts.tsx @@ -3,36 +3,31 @@ import { useDropzone } from 'react-dropzone'; import { useFileContext } from '../../../context/UsersFiles'; import { useEffect, useState } from 'react'; import { useCredentials } from '../../../context/UserCredentials'; -import { alertStateType, CustomFile, CustomFileBase, UserCredentials } from '../../../types'; +import { CustomFile, CustomFileBase, UserCredentials } from '../../../types'; import { chunkSize } from '../../../utils/Constants'; import { uploadAPI } from '../../../utils/FileAPI'; -import CustomAlert from '../../UI/Alert'; import { v4 as uuidv4 } from 'uuid'; import { LoadingSpinner } from '@neo4j-ndl/react'; +import { showErrorToast, showSuccessToast } from '../../../utils/toasts'; export default function DropZoneForSmallLayouts() { const { filesData, setFilesData, model } = useFileContext(); const [isLoading, setIsLoading] = useState(false); const [isClicked, setIsClicked] = useState(false); const { userCredentials } = useCredentials(); - const [alertDetails, setalertDetails] = useState({ - showAlert: false, - alertType: 'error', - alertMessage: '', - }); + const [selectedFiles, setSelectedFiles] = useState([]); useEffect(() => { if (selectedFiles.length > 0) { - selectedFiles.forEach((file, uid) => { - if (filesData[uid]?.status == 'None' && isClicked) { + for (let index = 0; index < selectedFiles.length; index++) { + const file = selectedFiles[index]; + if (filesData[index]?.status == 'None' && isClicked) { uploadFileInChunks(file); } - }); + } } }, [selectedFiles]); - const handleClose = () => { - setalertDetails((prev) => ({ ...prev, showAlert: false, alertMessage: '' })); - }; + const uploadFileInChunks = (file: File) => { const totalChunks = Math.ceil(file.size / chunkSize); const chunkProgressIncrement = 100 / totalChunks; @@ -110,17 +105,15 @@ export default function DropZoneForSmallLayouts() { } } catch (error) { setIsLoading(false); - setalertDetails({ - showAlert: true, - alertType: 'error', - alertMessage: 'Error Occurred', - }); + if (error instanceof Error) { + showErrorToast('Error Occurred'); + } setFilesData((prevfiles) => prevfiles.map((curfile) => { if (curfile.name == file.name) { return { ...curfile, - status: 'Failed', + status: 'Upload Failed', type: `${file.name.substring(file.name.lastIndexOf('.') + 1, file.name.length).toUpperCase()}`, }; } @@ -143,11 +136,7 @@ export default function DropZoneForSmallLayouts() { ); setIsClicked(false); setIsLoading(false); - setalertDetails({ - showAlert: true, - alertType: 'success', - alertMessage: `${file.name} uploaded successfully`, - }); + showSuccessToast(`${file.name} uploaded successfully`); } }; @@ -169,11 +158,7 @@ export default function DropZoneForSmallLayouts() { }, onDropRejected: (e) => { if (e.length) { - setalertDetails({ - showAlert: true, - alertType: 'error', - alertMessage: 'Failed To Upload, Unsupported file extention', - }); + showErrorToast('Failed To Upload, Unsupported file extention'); } }, disabled: isLoading, @@ -193,11 +178,13 @@ export default function DropZoneForSmallLayouts() { fileSource: 'local file', uploadprogess: 0, processingProgress: undefined, + retryOption: '', + retryOptionStatus: false, }; const copiedFilesData: CustomFile[] = [...filesData]; - - f.forEach((file) => { + for (let index = 0; index < f.length; index++) { + const file = f[index]; const filedataIndex = copiedFilesData.findIndex((filedataitem) => filedataitem?.name === file?.name); if (filedataIndex == -1) { copiedFilesData.unshift({ @@ -223,21 +210,13 @@ export default function DropZoneForSmallLayouts() { processingProgress: defaultValues.processingProgress, }); } - }); + } setFilesData(copiedFilesData); } }; console.log(acceptedFiles); return ( <> - {alertDetails.showAlert && ( - - )}
{isLoading ? : } diff --git a/frontend/src/components/FileTable.tsx b/frontend/src/components/FileTable.tsx index 23310eaf4..aa4d9bb9a 100644 --- a/frontend/src/components/FileTable.tsx +++ b/frontend/src/components/FileTable.tsx @@ -25,19 +25,17 @@ import { import { useFileContext } from '../context/UsersFiles'; import { getSourceNodes } from '../services/GetFiles'; import { v4 as uuidv4 } from 'uuid'; -import { statusCheck, capitalize } from '../utils/Utils'; import { - SourceNode, - CustomFile, - FileTableProps, - UserCredentials, - statusupdate, - alertStateType, - ChildRef, -} from '../types'; + statusCheck, + capitalize, + isFileCompleted, + calculateProcessedCount, + getFileSourceStatus, + isProcessingFileValid, +} from '../utils/Utils'; +import { SourceNode, CustomFile, FileTableProps, UserCredentials, statusupdate, ChildRef } from '../types'; import { useCredentials } from '../context/UserCredentials'; -import { MagnifyingGlassCircleIconSolid } from '@neo4j-ndl/react/icons'; -import CustomAlert from './UI/Alert'; +import { ArrowPathIconSolid, MagnifyingGlassCircleIconSolid } from '@neo4j-ndl/react/icons'; import CustomProgressBar from './UI/CustomProgressBar'; import subscribe from '../services/PollingAPI'; import { triggerStatusUpdateAPI } from '../services/ServerSideStatusUpdateAPI'; @@ -48,9 +46,10 @@ import cancelAPI from '../services/CancelAPI'; import IconButtonWithToolTip from './UI/IconButtonToolTip'; import { batchSize, largeFileSize, llms } from '../utils/Constants'; import IndeterminateCheckbox from './UI/CustomCheckBox'; +import { showErrorToast, showNormalToast } from '../utils/toasts'; let onlyfortheFirstRender = true; const FileTable = forwardRef((props, ref) => { - const { isExpanded, connectionStatus, setConnectionStatus, onInspect } = props; + const { isExpanded, connectionStatus, setConnectionStatus, onInspect, onRetry } = props; const { filesData, setFilesData, model, rowSelection, setRowSelection, setSelectedRows, setProcessedCount, queue } = useFileContext(); const { userCredentials } = useCredentials(); @@ -62,29 +61,15 @@ const FileTable = forwardRef((props, ref) => { const [fileSourceFilter, setFileSourceFilter] = useState(''); const [llmtypeFilter, setLLmtypeFilter] = useState(''); const skipPageResetRef = useRef(false); - const [alertDetails, setalertDetails] = useState({ - showAlert: false, - alertType: 'error', - alertMessage: '', - }); const tableRef = useRef(null); const { updateStatusForLargeFiles } = useServerSideEvent( (inMinutes, time, fileName) => { - setalertDetails({ - showAlert: true, - alertType: 'info', - alertMessage: `${fileName} will take approx ${time} ${inMinutes ? 'Min' : 'Sec'}`, - }); - localStorage.setItem('alertShown', JSON.stringify(true)); + showNormalToast(`${fileName} will take approx ${time} ${inMinutes ? 'Min' : 'Sec'}`); }, (fileName) => { - setalertDetails({ - showAlert: true, - alertType: 'error', - alertMessage: `${fileName} Failed to process`, - }); + showErrorToast(`${fileName} Failed to process`); } ); const columns = useMemo( @@ -117,7 +102,10 @@ const FileTable = forwardRef((props, ref) => { {...{ checked: row.getIsSelected(), disabled: - !row.getCanSelect() || row.original.status == 'Uploading' || row.original.status === 'Processing', + !row.getCanSelect() || + row.original.status == 'Uploading' || + row.original.status === 'Processing' || + row.original.status === 'Waiting', indeterminate: row.getIsSomeSelected(), onChange: row.getToggleSelectedHandler(), }} @@ -158,6 +146,22 @@ const FileTable = forwardRef((props, ref) => { > {info.getValue()} + {(info.getValue() === 'Completed' || + info.getValue() === 'Failed' || + info.getValue() === 'Cancelled') && ( + + onRetry(info?.row?.id as string)} + > + + + + )}
); } else if (info.getValue() === 'Processing' && info.row.original.processingProgress === undefined) { @@ -218,11 +222,17 @@ const FileTable = forwardRef((props, ref) => {
); } + return ( +
+ + {info.getValue()} +
+ ); }, header: () => Status, footer: (info) => info.column.id, filterFn: 'statusFilter' as any, - size: 200, + size: 250, meta: { columnActions: { actions: [ @@ -556,6 +566,37 @@ const FileTable = forwardRef((props, ref) => { skipPageResetRef.current = false; }, [filesData.length]); + const handleFileUploadError = (error: AxiosError) => { + // @ts-ignore + const errorfile = decodeURI(error?.config?.url?.split('?')[0].split('/').at(-1)); + setProcessedCount((prev) => Math.max(prev - 1, 0)); + setFilesData((prevfiles) => + prevfiles.map((curfile) => (curfile.name === errorfile ? { ...curfile, status: 'Failed' } : curfile)) + ); + }; + + const handleSmallFile = (item: SourceNode, userCredentials: UserCredentials) => { + subscribe( + item.fileName, + userCredentials?.uri, + userCredentials?.userName, + userCredentials?.database, + userCredentials?.password, + updatestatus, + updateProgress + ).catch(handleFileUploadError); + }; + + const handleLargeFile = (item: SourceNode, userCredentials: UserCredentials) => { + triggerStatusUpdateAPI( + item.fileName, + userCredentials.uri, + userCredentials.userName, + userCredentials.password, + userCredentials.database, + updateStatusForLargeFiles + ); + }; useEffect(() => { const waitingQueue: CustomFile[] = JSON.parse( localStorage.getItem('waitingQueue') ?? JSON.stringify({ queue: [] }) @@ -577,10 +618,14 @@ const FileTable = forwardRef((props, ref) => { if (res.data.status !== 'Failed') { const prefiles: CustomFile[] = []; if (res.data.data.length) { - res.data.data.forEach((item: SourceNode) => { + res.data.data.forEach((item) => { if (item.fileName != undefined && item.fileName.length) { const waitingFile = waitingQueue.length && waitingQueue.find((f: CustomFile) => f.name === item.fileName); + if (isFileCompleted(waitingFile as CustomFile, item)) { + setProcessedCount((prev) => calculateProcessedCount(prev, batchSize)); + queue.remove(item.fileName); + } if (waitingFile && item.status === 'Completed') { setProcessedCount((prev) => { if (prev === batchSize) { @@ -599,21 +644,8 @@ const FileTable = forwardRef((props, ref) => { NodesCount: item?.nodeCount ?? 0, processing: item?.processingTime ?? 'None', relationshipCount: item?.relationshipCount ?? 0, - status: waitingFile - ? 'Waiting' - : item?.fileSource === 's3 bucket' && localStorage.getItem('accesskey') === item?.awsAccessKeyId - ? item?.status - : item?.fileSource === 'local file' - ? item?.status - : item?.status === 'Completed' || item.status === 'Failed' - ? item?.status - : item?.fileSource === 'Wikipedia' || - item?.fileSource === 'youtube' || - item?.fileSource === 'gcs bucket' || - item?.fileSource === 'web-url' - ? item?.status - : 'N/A', - model: waitingFile ? waitingFile.model : item?.model ?? model, + status: waitingFile ? 'Waiting' : getFileSourceStatus(item), + model: item?.model ?? model, id: !waitingFile ? uuidv4() : waitingFile.id, source_url: item?.url != 'None' && item?.url != '' ? item.url : '', fileSource: item?.fileSource ?? 'None', @@ -629,58 +661,17 @@ const FileTable = forwardRef((props, ref) => { !isNaN(Math.floor((item?.processed_chunk / item?.total_chunks) * 100)) ? Math.floor((item?.processed_chunk / item?.total_chunks) * 100) : undefined, - // total_pages: item?.total_pages ?? 0, access_token: item?.access_token ?? '', + retryOption: item.retry_condition ?? '', + retryOptionStatus: false, }); } }); res.data.data.forEach((item) => { - if ( - item.status === 'Processing' && - item.fileName != undefined && - userCredentials && - userCredentials.database - ) { - if (item?.fileSize < largeFileSize) { - subscribe( - item.fileName, - userCredentials?.uri, - userCredentials?.userName, - userCredentials?.database, - userCredentials?.password, - updatestatus, - updateProgress - ).catch((error: AxiosError) => { - // @ts-ignore - const errorfile = decodeURI(error?.config?.url?.split('?')[0].split('/').at(-1)); - setProcessedCount((prev) => { - if (prev == batchSize) { - return batchSize - 1; - } - return prev + 1; - }); - setFilesData((prevfiles) => { - return prevfiles.map((curfile) => { - if (curfile.name == errorfile) { - return { - ...curfile, - status: 'Failed', - }; - } - return curfile; - }); - }); - }); - } else { - triggerStatusUpdateAPI( - item.fileName, - userCredentials.uri, - userCredentials.userName, - userCredentials.password, - userCredentials.database, - updateStatusForLargeFiles - ); - } + if (isProcessingFileValid(item, userCredentials as UserCredentials)) { + item.fileSize < largeFileSize + ? handleSmallFile(item, userCredentials as UserCredentials) + : handleLargeFile(item, userCredentials as UserCredentials); } }); } else { @@ -693,11 +684,10 @@ const FileTable = forwardRef((props, ref) => { } setIsLoading(false); } catch (error: any) { - setalertDetails({ - showAlert: true, - alertType: 'error', - alertMessage: error.message, - }); + if (error instanceof Error) { + showErrorToast(error.message); + } + setIsLoading(false); setConnectionStatus(false); setFilesData([]); @@ -717,11 +707,7 @@ const FileTable = forwardRef((props, ref) => { if (processingFilesCount === 1) { setProcessedCount(1); } - setalertDetails({ - showAlert: true, - alertType: 'info', - alertMessage: `Files are in processing please wait till previous batch completes`, - }); + showNormalToast(`Files are in processing please wait till previous batch completes`); } else { const waitingQueue: CustomFile[] = JSON.parse( localStorage.getItem('waitingQueue') ?? JSON.stringify({ queue: [] }) @@ -788,11 +774,7 @@ const FileTable = forwardRef((props, ref) => { const error = JSON.parse(err.message); if (Object.keys(error).includes('fileName')) { const { message } = error; - setalertDetails({ - showAlert: true, - alertType: 'error', - alertMessage: message, - }); + showErrorToast(message); } } } @@ -870,11 +852,12 @@ const FileTable = forwardRef((props, ref) => { // Component has content, calculate maximum height for table // Observes the height of the content and calculates own height accordingly const resizeObserver = new ResizeObserver((entries) => { - entries.forEach((entry) => { + for (let index = 0; index < entries.length; index++) { + const entry = entries[index]; const { height } = entry.contentRect; const rowHeight = document?.getElementsByClassName('ndl-data-grid-td')?.[0]?.clientHeight ?? 69; table.setPageSize(Math.floor(height / rowHeight)); - }); + } }); const [contentElement] = document.getElementsByClassName('ndl-data-grid-scrollable'); @@ -889,24 +872,12 @@ const FileTable = forwardRef((props, ref) => { const classNameCheck = isExpanded ? 'fileTableWithExpansion' : `filetable`; - const handleClose = () => { - setalertDetails((prev) => ({ ...prev, showAlert: false })); - localStorage.setItem('alertShown', JSON.stringify(true)); - }; useEffect(() => { setSelectedRows(table.getSelectedRowModel().rows.map((i) => i.id)); }, [table.getSelectedRowModel()]); return ( <> - {alertDetails.showAlert && ( - - )} {filesData ? ( <>
diff --git a/frontend/src/components/Layout/PageLayout.tsx b/frontend/src/components/Layout/PageLayout.tsx index 8361ad3cd..c2c21116c 100644 --- a/frontend/src/components/Layout/PageLayout.tsx +++ b/frontend/src/components/Layout/PageLayout.tsx @@ -6,13 +6,11 @@ import Content from '../Content'; import SettingsModal from '../Popups/Settings/SettingModal'; import { clearChatAPI } from '../../services/QnaAPI'; import { useCredentials } from '../../context/UserCredentials'; -import { UserCredentials, alertStateType } from '../../types'; +import { UserCredentials } from '../../types'; import { useMessageContext } from '../../context/UserMessages'; -import { AlertColor, AlertPropsColorOverrides, useMediaQuery } from '@mui/material'; -import { OverridableStringUnion } from '@mui/types'; +import { useMediaQuery } from '@mui/material'; import { useFileContext } from '../../context/UsersFiles'; import SchemaFromTextDialog from '../Popups/Settings/SchemaFromText'; -import CustomAlert from '../UI/Alert'; export default function PageLayoutNew({ isSettingPanelExpanded, @@ -48,11 +46,7 @@ export default function PageLayoutNew({ setIsRightExpanded(false); } }; - const [alertDetails, setalertDetails] = useState({ - showAlert: false, - alertType: 'error', - alertMessage: '', - }); + const { messages } = useMessageContext(); const { isSchema, setIsSchema, setShowTextFromSchemaDialog, showTextFromSchemaDialog } = useFileContext(); @@ -72,30 +66,8 @@ export default function PageLayoutNew({ } }; - const showAlert = ( - alertmsg: string, - alerttype: OverridableStringUnion | undefined - ) => { - setalertDetails({ - showAlert: true, - alertMessage: alertmsg, - alertType: alerttype, - }); - }; - const handleClose = () => { - setalertDetails((prev) => ({ ...prev, showAlert: false, alertMessage: '' })); - }; - return (
- {alertDetails.showAlert && ( - - )} { diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx index 373007e95..24de576c5 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx @@ -179,9 +179,10 @@ export default function DeletePopUpForOrphanNodes({ await deleteHandler(table.getSelectedRowModel().rows.map((r) => r.id)); const selectedRows = table.getSelectedRowModel().rows.map((r) => r.id); setTotalOrphanNodes((prev) => prev - selectedRows.length); - selectedRows.forEach((eid: string) => { + for (let index = 0; index < selectedRows.length; index++) { + const eid: string = selectedRows[index]; setOrphanNodes((prev) => prev.filter((node) => node.e.elementId != eid)); - }); + } setshowDeletePopUp(false); if (totalOrphanNodes) { await fetchOrphanNodes(); diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/EnitityExtraction/EntityExtractionSetting.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/EnitityExtraction/EntityExtractionSetting.tsx index cca1a09a3..37f283d2a 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/EnitityExtraction/EntityExtractionSetting.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/EnitityExtraction/EntityExtractionSetting.tsx @@ -5,11 +5,11 @@ import { Dropdown, Flex, Typography, useMediaQuery } from '@neo4j-ndl/react'; import { useCredentials } from '../../../../context/UserCredentials'; import { useFileContext } from '../../../../context/UsersFiles'; import { OnChangeValue, ActionMeta } from 'react-select'; -import { OptionType, OptionTypeForExamples, schema, UserCredentials } from '../../../../types'; -import { useAlertContext } from '../../../../context/Alert'; +import { OptionType, schema, UserCredentials } from '../../../../types'; import { getNodeLabelsAndRelTypes } from '../../../../services/GetNodeLabelsRelTypes'; import schemaExamples from '../../../../assets/schemas.json'; import { tokens } from '@neo4j-ndl/base'; +import { showNormalToast } from '../../../../utils/toasts'; export default function EntityExtractionSetting({ view, @@ -82,9 +82,15 @@ export default function EntityExtractionSetting({ const nodesFromSchema = selectedOptions.map((s) => JSON.parse(s.value).nodelabels).flat(); const relationsFromSchema = selectedOptions.map((s) => JSON.parse(s.value).relationshipTypes).flat(); let nodeOptionsFromSchema: OptionType[] = []; - nodesFromSchema.forEach((n) => nodeOptionsFromSchema.push({ label: n, value: n })); + for (let index = 0; index < nodesFromSchema.length; index++) { + const n = nodesFromSchema[index]; + nodeOptionsFromSchema.push({ label: n, value: n }); + } let relationshipOptionsFromSchema: OptionType[] = []; - relationsFromSchema.forEach((r) => relationshipOptionsFromSchema.push({ label: r, value: r })); + for (let index = 0; index < relationsFromSchema.length; index++) { + const r = relationsFromSchema[index]; + relationshipOptionsFromSchema.push({ label: r, value: r }); + } setSelectedNodes((prev) => { const combinedData = [...prev, ...nodeOptionsFromSchema]; const uniqueLabels = new Set(); @@ -145,11 +151,9 @@ export default function EntityExtractionSetting({ const [relationshipTypeOptions, setrelationshipTypeOptions] = useState([]); const [defaultExamples, setdefaultExamples] = useState([]); - const { showAlert } = useAlertContext(); - useEffect(() => { - const parsedData = schemaExamples.reduce((accu: OptionTypeForExamples[], example) => { - const examplevalues: OptionTypeForExamples = { + const parsedData = schemaExamples.reduce((accu: OptionType[], example) => { + const examplevalues: OptionType = { label: example.schema, value: JSON.stringify({ nodelabels: example.labels, @@ -227,7 +231,7 @@ export default function EntityExtractionSetting({ JSON.stringify({ db: userCredentials?.uri, selectedOptions: [] }) ); localStorage.setItem('selectedSchemas', JSON.stringify({ db: userCredentials?.uri, selectedOptions: [] })); - showAlert('info', `Successfully Removed the Schema settings`); + showNormalToast(`Successfully Removed the Schema settings`); if (view === 'Dialog' && onClose != undefined) { onClose(); } diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/index.tsx index 84577c53c..dda797971 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/index.tsx @@ -6,8 +6,6 @@ import deleteOrphanAPI from '../../../services/DeleteOrphanNodes'; import { UserCredentials } from '../../../types'; import { useCredentials } from '../../../context/UserCredentials'; import EntityExtractionSettings from './EnitityExtraction/EntityExtractionSetting'; -import { AlertColor, AlertPropsColorOverrides } from '@mui/material'; -import { OverridableStringUnion } from '@mui/types'; import { useFileContext } from '../../../context/UsersFiles'; import DeduplicationTab from './Deduplication'; import { tokens } from '@neo4j-ndl/base'; @@ -20,10 +18,6 @@ export default function GraphEnhancementDialog({ }: { open: boolean; onClose: () => void; - showAlert: ( - alertmsg: string, - alerttype: OverridableStringUnion | undefined - ) => void; closeSettingModal: () => void; }) { const { breakpoints } = tokens; diff --git a/frontend/src/components/Popups/LargeFilePopUp/ConfirmationDialog.tsx b/frontend/src/components/Popups/LargeFilePopUp/ConfirmationDialog.tsx index 50dbf6095..8d04467ff 100644 --- a/frontend/src/components/Popups/LargeFilePopUp/ConfirmationDialog.tsx +++ b/frontend/src/components/Popups/LargeFilePopUp/ConfirmationDialog.tsx @@ -91,12 +91,13 @@ export default function ConfirmationDialog({ extractHandler(selectedRows); } else { const tobeProcessFiles: CustomFile[] = []; - checked.forEach((id: string) => { + for (let index = 0; index < checked.length; index++) { + const id = checked[index]; const file = filesData.find((f) => f.id === id); if (file) { tobeProcessFiles.push(file); } - }); + } extractHandler(tobeProcessFiles); } setChecked([]); diff --git a/frontend/src/components/Popups/LargeFilePopUp/LargeFilesAlert.tsx b/frontend/src/components/Popups/LargeFilePopUp/LargeFilesAlert.tsx index 26c9cfcda..cc684156b 100644 --- a/frontend/src/components/Popups/LargeFilePopUp/LargeFilesAlert.tsx +++ b/frontend/src/components/Popups/LargeFilePopUp/LargeFilesAlert.tsx @@ -7,6 +7,7 @@ import { chunkSize } from '../../../utils/Constants'; import BellImage from '../../../assets/images/Stopwatch-blue.svg'; import AlertIcon from '../../Layout/AlertIcon'; import wikipedialogo from '../../../assets/images/wikipedia.svg'; +import wikipediadark from '../../../assets/images/wikipedia-darkmode.svg'; import youtubelogo from '../../../assets/images/youtube.svg'; import weblogo from '../../../assets/images/web.svg'; import webdarkmode from '../../../assets/images/web-darkmode.svg'; @@ -20,7 +21,7 @@ const LargeFilesAlert: FC = ({ largeFiles, handleToggle, checke const imageIcon: Record = useMemo( () => ({ - Wikipedia: wikipedialogo, + Wikipedia: colorMode === 'dark' ? wikipedialogo : wikipediadark, 'gcs bucket': gcslogo, youtube: youtubelogo, 's3 bucket': s3logo, diff --git a/frontend/src/components/Popups/RetryConfirmation/Index.tsx b/frontend/src/components/Popups/RetryConfirmation/Index.tsx new file mode 100644 index 000000000..d7b160e8e --- /dev/null +++ b/frontend/src/components/Popups/RetryConfirmation/Index.tsx @@ -0,0 +1,84 @@ +import { Banner, Dialog, Flex, Radio } from '@neo4j-ndl/react'; +import { RETRY_OPIONS } from '../../../utils/Constants'; +import { useFileContext } from '../../../context/UsersFiles'; +import { capitalize } from '../../../utils/Utils'; +import { BannerAlertProps } from '../../../types'; +import ButtonWithToolTip from '../../UI/ButtonWithToolTip'; + +export default function RetryConfirmationDialog({ + open, + onClose, + fileId, + retryLoading, + retryHandler, + alertStatus, + onBannerClose, +}: { + open: boolean; + onClose: () => void; + fileId: string; + retryLoading: boolean; + alertStatus: BannerAlertProps; + retryHandler: (filename: string, retryoption: string) => void; + onBannerClose: () => void; +}) { + const { filesData, setFilesData } = useFileContext(); + const file = filesData.find((c) => c.id === fileId); + const RetryOptionsForFile = file?.status != 'Completed' ? RETRY_OPIONS : RETRY_OPIONS.slice(0, 2); + return ( + + Reprocess Options + + {alertStatus.showAlert && ( + + {alertStatus.alertMessage} + + )} + + {RetryOptionsForFile.map((o, i) => { + return ( + { + setFilesData((prev) => { + return prev.map((f) => { + return f.id === fileId ? { ...f, retryOptionStatus: e.target.checked, retryOption: o } : f; + }); + }); + }} + name='retryoptions' + checked={o === file?.retryOption && file?.retryOptionStatus} + label={o + .split('_') + .map((s) => capitalize(s)) + .join(' ')} + onKeyDown={(e) => { + if (e.code === 'Enter' && file?.retryOption.length) { + retryHandler(file?.name as string, file?.retryOption as string); + } + }} + /> + ); + })} + + + + { + retryHandler(file?.name as string, file?.retryOption as string); + }} + size='large' + > + Continue + + + + + + ); +} diff --git a/frontend/src/components/Popups/Settings/SchemaFromText.tsx b/frontend/src/components/Popups/Settings/SchemaFromText.tsx index 58a605edc..8ebc15020 100644 --- a/frontend/src/components/Popups/Settings/SchemaFromText.tsx +++ b/frontend/src/components/Popups/Settings/SchemaFromText.tsx @@ -3,24 +3,18 @@ import { useCallback, useState } from 'react'; import { getNodeLabelsAndRelTypesFromText } from '../../../services/SchemaFromTextAPI'; import { useCredentials } from '../../../context/UserCredentials'; import { useFileContext } from '../../../context/UsersFiles'; -import { AlertColor, AlertPropsColorOverrides } from '@mui/material'; -import { OverridableStringUnion } from '@mui/types'; import { buttonCaptions } from '../../../utils/Constants'; import ButtonWithToolTip from '../../UI/ButtonWithToolTip'; +import { showNormalToast, showSuccessToast } from '../../../utils/toasts'; const SchemaFromTextDialog = ({ open, onClose, openSettingsDialog, - showAlert, }: { open: boolean; onClose: () => void; openSettingsDialog: () => void; - showAlert: ( - alertmsg: string, - alerttype: OverridableStringUnion | undefined - ) => void; }) => { const [userText, setUserText] = useState(''); const [loading, setloading] = useState(false); @@ -75,19 +69,15 @@ const SchemaFromTextDialog = ({ }); } if (response.data?.data?.relationshipTypes.length && response.data?.data?.labels.length) { - showAlert( - `Successfully Created ${response.data?.data?.labels.length} Node labels and ${response.data?.data?.relationshipTypes.length} Relationship labels`, - 'success' + showSuccessToast( + `Successfully Created ${response.data?.data?.labels.length} Node labels and ${response.data?.data?.relationshipTypes.length} Relationship labels` ); } else if (response.data?.data?.relationshipTypes.length && !response.data?.data?.labels.length) { - showAlert( - `Successfully Created ${response.data?.data?.relationshipTypes.length} Relationship labels`, - 'success' - ); + showSuccessToast(`Successfully Created ${response.data?.data?.relationshipTypes.length} Relationship labels`); } else if (!response.data?.data?.relationshipTypes.length && response.data?.data?.labels.length) { - showAlert(`Successfully Created ${response.data?.data?.labels.length} Node labels`, 'success'); + showSuccessToast(`Successfully Created ${response.data?.data?.labels.length} Node labels`); } else { - showAlert(`Please give meaningfull text`, 'success'); + showNormalToast(`Please give meaningfull text`); } } else { throw new Error('Unable to create labels from '); diff --git a/frontend/src/components/Popups/Settings/SettingModal.tsx b/frontend/src/components/Popups/Settings/SettingModal.tsx index 504ad88d4..8a2e35beb 100644 --- a/frontend/src/components/Popups/Settings/SettingModal.tsx +++ b/frontend/src/components/Popups/Settings/SettingModal.tsx @@ -1,6 +1,6 @@ import { Dialog, Dropdown } from '@neo4j-ndl/react'; import { OnChangeValue, ActionMeta } from 'react-select'; -import { OptionType, OptionTypeForExamples, SettingsModalProps, UserCredentials, schema } from '../../../types'; +import { OptionType, SettingsModalProps, UserCredentials, schema } from '../../../types'; import { useFileContext } from '../../../context/UsersFiles'; import { getNodeLabelsAndRelTypes } from '../../../services/GetNodeLabelsRelTypes'; import { useCredentials } from '../../../context/UserCredentials'; @@ -63,9 +63,15 @@ const SettingsModal: React.FC = ({ const nodesFromSchema = selectedOptions.map((s) => JSON.parse(s.value).nodelabels).flat(); const relationsFromSchema = selectedOptions.map((s) => JSON.parse(s.value).relationshipTypes).flat(); let nodeOptionsFromSchema: OptionType[] = []; - nodesFromSchema.forEach((n) => nodeOptionsFromSchema.push({ label: n, value: n })); + for (let index = 0; index < nodesFromSchema.length; index++) { + const n = nodesFromSchema[index]; + nodeOptionsFromSchema.push({ label: n, value: n }); + } let relationshipOptionsFromSchema: OptionType[] = []; - relationsFromSchema.forEach((r) => relationshipOptionsFromSchema.push({ label: r, value: r })); + for (let index = 0; index < relationsFromSchema.length; index++) { + const r = relationsFromSchema[index]; + relationshipOptionsFromSchema.push({ label: r, value: r }); + } setSelectedNodes((prev) => { const combinedData = [...prev, ...nodeOptionsFromSchema]; const uniqueLabels = new Set(); @@ -123,8 +129,8 @@ const SettingsModal: React.FC = ({ const { showAlert } = useAlertContext(); useEffect(() => { - const parsedData = schemaExamples.reduce((accu: OptionTypeForExamples[], example) => { - const examplevalues: OptionTypeForExamples = { + const parsedData = schemaExamples.reduce((accu: OptionType[], example) => { + const examplevalues: OptionType = { label: example.schema, value: JSON.stringify({ nodelabels: example.labels, diff --git a/frontend/src/components/WebSources/CustomSourceInput.tsx b/frontend/src/components/WebSources/CustomSourceInput.tsx index e03c4c185..5775e35a9 100644 --- a/frontend/src/components/WebSources/CustomSourceInput.tsx +++ b/frontend/src/components/WebSources/CustomSourceInput.tsx @@ -48,6 +48,11 @@ export default function CustomSourceInput({ onChange={onChangeHandler} errorText={!isValid && isFocused && 'Please Fill The Valid URL'} onPaste={onPasteHandler} + onKeyDown={(e) => { + if (e.code === 'Enter') { + submitHandler(value); + } + }} />
diff --git a/frontend/src/hooks/useSourceInput.tsx b/frontend/src/hooks/useSourceInput.tsx index 602acb947..eae33e3d4 100644 --- a/frontend/src/hooks/useSourceInput.tsx +++ b/frontend/src/hooks/useSourceInput.tsx @@ -1,5 +1,5 @@ import React, { useCallback, useState } from 'react'; -import { CustomFile, CustomFileBase, ScanProps, UserCredentials, fileName } from '../types'; +import { CustomFile, CustomFileBase, ScanProps, UserCredentials } from '../types'; import { useFileContext } from '../context/UsersFiles'; import { useCredentials } from '../context/UserCredentials'; import { urlScanAPI } from '../services/URLScan'; @@ -55,6 +55,8 @@ export default function useSourceInput( model: model, fileSource: fileSource, processingProgress: undefined, + retryOption: '', + retryOptionStatus: false, }; if (url.trim() != '') { setIsValid(validator(url) && isFocused); @@ -105,37 +107,40 @@ export default function useSourceInput( } const copiedFilesData: CustomFile[] = [...filesData]; - apiResponse?.data?.file_name?.forEach((item: fileName) => { - const filedataIndex = copiedFilesData.findIndex((filedataitem) => filedataitem?.name === item?.fileName); - if (filedataIndex == -1) { - const baseValues = { - name: item.fileName, - size: item.fileSize, - source_url: item.url, - id: uuidv4(), - language: item.language, - // total_pages: 1, - ...defaultValues, - }; - if (isWikiQuery) { - baseValues.wiki_query = item.fileName; + if (apiResponse?.data?.file_name?.length) { + for (let index = 0; index < apiResponse?.data?.file_name.length; index++) { + const item = apiResponse?.data?.file_name[index]; + const filedataIndex = copiedFilesData.findIndex((filedataitem) => filedataitem?.name === item?.fileName); + if (filedataIndex == -1) { + const baseValues = { + name: item.fileName, + size: item.fileSize, + source_url: item.url, + id: uuidv4(), + language: item.language, + // total_pages: 1, + ...defaultValues, + }; + if (isWikiQuery) { + baseValues.wiki_query = item.fileName; + } + copiedFilesData.unshift(baseValues); + } else { + const tempFileData = copiedFilesData[filedataIndex]; + copiedFilesData.splice(filedataIndex, 1); + copiedFilesData.unshift({ + ...tempFileData, + status: defaultValues.status, + NodesCount: defaultValues.NodesCount, + relationshipCount: defaultValues.relationshipCount, + processing: defaultValues.processing, + model: defaultValues.model, + fileSource: defaultValues.fileSource, + processingProgress: defaultValues.processingProgress, + }); } - copiedFilesData.unshift(baseValues); - } else { - const tempFileData = copiedFilesData[filedataIndex]; - copiedFilesData.splice(filedataIndex, 1); - copiedFilesData.unshift({ - ...tempFileData, - status: defaultValues.status, - NodesCount: defaultValues.NodesCount, - relationshipCount: defaultValues.relationshipCount, - processing: defaultValues.processing, - model: defaultValues.model, - fileSource: defaultValues.fileSource, - processingProgress: defaultValues.processingProgress, - }); } - }); + } setFilesData(copiedFilesData); setInputVal(''); setIsValid(false); diff --git a/frontend/src/services/CommonAPI.ts b/frontend/src/services/CommonAPI.ts index bbae83032..b55d002fe 100644 --- a/frontend/src/services/CommonAPI.ts +++ b/frontend/src/services/CommonAPI.ts @@ -7,7 +7,7 @@ const apiCall = async ( url: string, method: Method, commonParams: UserCredentials, - additionalParams: FormDataParams + additionalParams: Partial ) => { try { const formData = new FormData(); diff --git a/frontend/src/services/retry.ts b/frontend/src/services/retry.ts new file mode 100644 index 000000000..6c1b6c28c --- /dev/null +++ b/frontend/src/services/retry.ts @@ -0,0 +1,23 @@ +import axios from 'axios'; +import { url } from '../utils/Utils'; +import { UserCredentials, commonserverresponse } from '../types'; + +const retry = async (userCredentials: UserCredentials, file: string, retryOption: string) => { + try { + const formData = new FormData(); + + formData.append('uri', userCredentials?.uri ?? ''); + formData.append('database', userCredentials?.database ?? ''); + formData.append('userName', userCredentials?.userName ?? ''); + formData.append('password', userCredentials?.password ?? ''); + + formData.append('file_name', file); + formData.append('retry_condition', retryOption); + const response = await axios.post(`${url()}/retry_processing`, formData); + return response; + } catch (error) { + console.log('Error Posting the Question:', error); + throw error; + } +}; +export default retry; diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 2802a2d6b..d16f56fa1 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -4,6 +4,7 @@ import React, { Dispatch, ReactNode, SetStateAction } from 'react'; import { OverridableStringUnion } from '@mui/types'; import type { Node, Relationship } from '@neo4j-nvl/base'; import { NonOAuthError } from '@react-oauth/google'; +import { BannerType } from '@neo4j-ndl/react'; export interface CustomFileBase extends Partial { processing: number | string; @@ -24,10 +25,11 @@ export interface CustomFileBase extends Partial { processingProgress?: number; access_token?: string; checked?: boolean; + retryOptionStatus: boolean; + retryOption: string; } export interface CustomFile extends CustomFileBase { id: string; - // total_pages: number | 'N/A'; } export interface OptionType { @@ -35,11 +37,6 @@ export interface OptionType { readonly label: string; } -export interface OptionTypeForExamples { - readonly value: string; - readonly label: string; -} - export type UserCredentials = { uri: string; userName: string; @@ -47,14 +44,27 @@ export type UserCredentials = { database: string; } & { [key: string]: any }; -export type ExtractParams = { +export interface SourceNode extends Omit { + fileName: string; + fileSize: number; + fileType: string; + nodeCount?: number; + processingTime?: string; + relationshipCount?: number; + url?: string; + awsAccessKeyId?: string; + uploadprogress?: number; + gcsProjectId?: string; + processed_chunk?: number; + total_chunks?: number; + retry_condition?: string; +} + +export type ExtractParams = Pick & { file?: File; - model: string; - source_url?: string; aws_access_key_id?: string | null; aws_secret_access_key?: string | null; max_sources?: number; - wiki_query?: string; gcs_bucket_name?: string; gcs_bucket_folder?: string; gcs_blob_filename?: string; @@ -63,8 +73,7 @@ export type ExtractParams = { allowedNodes?: string[]; allowedRelationship?: string[]; gcs_project_id?: string; - language?: string; - access_token?: string; + retry_condition: string; } & { [key: string]: any }; export type UploadParams = { @@ -96,36 +105,10 @@ export interface S3ModalProps { hideModal: () => void; open: boolean; } -export interface GCSModalProps { - hideModal: () => void; - open: boolean; +export interface GCSModalProps extends Omit { openGCSModal: () => void; } -export interface SourceNode { - fileName: string; - fileSize: number; - fileType: string; - nodeCount?: number; - processingTime?: string; - relationshipCount?: number; - model: string; - status: string; - url?: string; - awsAccessKeyId?: string; - fileSource: string; - gcsBucket?: string; - gcsBucketFolder?: string; - errorMessage?: string; - uploadprogress?: number; - gcsProjectId?: string; - language?: string; - processed_chunk?: number; - total_chunks?: number; - // total_pages?: number; - access_token?: string; -} - export interface SideNavProps { isExpanded: boolean; position: 'left' | 'right'; @@ -171,6 +154,7 @@ export interface FileTableProps { setConnectionStatus: Dispatch>; onInspect: (id: string) => void; handleGenerateGraph: () => void; + onRetry: (id: string) => void; } export interface CustomModalProps { @@ -249,10 +233,7 @@ export type ChatbotProps = { isFullScreen?: boolean; connectionStatus: boolean; }; -export interface WikipediaModalTypes { - hideModal: () => void; - open: boolean; -} +export interface WikipediaModalTypes extends Omit {} export interface GraphViewModalProps { open: boolean; @@ -341,7 +322,9 @@ export type alertStateType = { alertType: OverridableStringUnion | undefined; alertMessage: string; }; - +export interface BannerAlertProps extends Omit { + alertType: BannerType; +} export type Scheme = Record; export type LabelCount = Record; @@ -437,19 +420,11 @@ export interface chatInfoMessage extends Partial { error: string; } -export interface eventResponsetypes { - fileName: string; - status: string; - processingTime: number; - nodeCount: number; - relationshipCount: number; - model: string; +export interface eventResponsetypes extends Omit { total_chunks: number | null; - // total_pages: number; - fileSize: number; - processed_chunk?: number; - fileSource: string; + processingTime: number; } + export type Nullable = Type | null; export type LabelColors = 'default' | 'success' | 'info' | 'warning' | 'danger' | undefined; diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index 47f1e119f..114b20fa0 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -185,7 +185,11 @@ export const POST_PROCESSING_JOBS: { title: string; description: string }[] = [ performing similarity-based searches.`, }, ]; - +export const RETRY_OPIONS = [ + 'start_from_beginning', + 'delete_entities_and_start_from_beginning', + 'start_from_last_processed_position', +]; export const batchSize: number = parseInt(process.env.VITE_BATCH_SIZE ?? '2'); export const nvlOptions: NvlOptions = { diff --git a/frontend/src/utils/FileAPI.ts b/frontend/src/utils/FileAPI.ts index b6dcabeba..2d248260f 100644 --- a/frontend/src/utils/FileAPI.ts +++ b/frontend/src/utils/FileAPI.ts @@ -25,6 +25,7 @@ export const extractAPI = async ( model: string, userCredentials: UserCredentials, source_type: string, + retry_condition: string, source_url?: string, aws_access_key_id?: string | null, aws_secret_access_key?: string | null, @@ -51,6 +52,7 @@ export const extractAPI = async ( file_name, allowedNodes, allowedRelationship, + retry_condition, }; } else if (source_type === 'Wikipedia') { additionalParams = { @@ -61,6 +63,7 @@ export const extractAPI = async ( allowedNodes, allowedRelationship, language, + retry_condition, }; } else if (source_type === 'gcs bucket') { additionalParams = { @@ -74,6 +77,7 @@ export const extractAPI = async ( allowedRelationship, gcs_project_id, access_token, + retry_condition, }; } else if (source_type === 'youtube') { additionalParams = { @@ -83,6 +87,7 @@ export const extractAPI = async ( file_name, allowedNodes, allowedRelationship, + retry_condition, }; } else if (source_type === 'web-url') { additionalParams = { @@ -92,6 +97,7 @@ export const extractAPI = async ( file_name, allowedNodes, allowedRelationship, + retry_condition, }; } else { additionalParams = { @@ -100,6 +106,7 @@ export const extractAPI = async ( file_name, allowedNodes, allowedRelationship, + retry_condition, }; } const response = await apiCall(urlExtract, method, commonParams, additionalParams); diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index 0b8b05841..8b49c7e7d 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -1,6 +1,16 @@ import { calcWordColor } from '@neo4j-devtools/word-color'; import type { Relationship } from '@neo4j-nvl/base'; -import { Entity, ExtendedNode, ExtendedRelationship, GraphType, Messages, Scheme } from '../types'; +import { + CustomFile, + Entity, + ExtendedNode, + ExtendedRelationship, + GraphType, + Messages, + Scheme, + SourceNode, + UserCredentials, +} from '../types'; // Get the Url export const url = () => { @@ -48,6 +58,10 @@ export const statusCheck = (status: string) => { return 'warning'; case 'Failed': return 'danger'; + case 'Upload Failed': + return 'danger'; + case 'Reprocess': + return 'info'; default: return 'unknown'; } @@ -134,12 +148,13 @@ export const processGraphData = (neoNodes: ExtendedNode[], neoRels: ExtendedRela const schemeVal: Scheme = {}; let iterator = 0; const labels: string[] = neoNodes.map((f: any) => f.labels); - labels.forEach((label: any) => { + for (let index = 0; index < labels.length; index++) { + const label = labels[index]; if (schemeVal[label] == undefined) { schemeVal[label] = calcWordColor(label[0]); iterator += 1; } - }); + } const newNodes: ExtendedNode[] = neoNodes.map((g: any) => { return { id: g.element_id, @@ -240,6 +255,35 @@ export const titleCheck = (title: string) => { return title === 'Chunk' || title === 'Document'; }; +export const getFileSourceStatus = (item: SourceNode) => { + if (item?.fileSource === 's3 bucket' && localStorage.getItem('accesskey') === item?.awsAccessKeyId) { + return item?.status; + } + if (item?.fileSource === 'local file') { + return item?.status; + } + if (item?.status === 'Completed' || item.status === 'Failed' || item.status === 'Reprocess') { + return item?.status; + } + if ( + item?.fileSource === 'Wikipedia' || + item?.fileSource === 'youtube' || + item?.fileSource === 'gcs bucket' || + item?.fileSource === 'web-url' + ) { + return item?.status; + } + return 'N/A'; +}; +export const isFileCompleted = (waitingFile: CustomFile, item: SourceNode) => + waitingFile && item.status === 'Completed'; + +export const calculateProcessedCount = (prev: number, batchSize: number) => + (prev === batchSize ? batchSize - 1 : prev + 1); + +export const isProcessingFileValid = (item: SourceNode, userCredentials: UserCredentials) => { + return item.status === 'Processing' && item.fileName != undefined && userCredentials && userCredentials.database; +}; export const sortAlphabetically = (a: Relationship, b: Relationship) => { const captionOne = a.caption?.toLowerCase() || ''; const captionTwo = b.caption?.toLowerCase() || ''; diff --git a/frontend/src/utils/toasts.ts b/frontend/src/utils/toasts.ts new file mode 100644 index 000000000..832c33b9a --- /dev/null +++ b/frontend/src/utils/toasts.ts @@ -0,0 +1,22 @@ +import { toast } from '@neo4j-ndl/react'; + +export const showErrorToast = (message: string, shouldAutoClose: boolean = true) => { + return toast.danger(message, { + isCloseable: true, + shouldAutoClose: shouldAutoClose, + }); +}; + +export const showSuccessToast = (message: string) => { + return toast.success(message, { + isCloseable: true, + shouldAutoClose: true, + }); +}; + +export const showNormalToast = (message: string) => { + return toast.neutral(message, { + isCloseable: true, + shouldAutoClose: true, + }); +}; diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 3915845ef..977740e94 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -1862,6 +1862,7 @@ dependencies: "@react-types/shared" "^3.24.1" + "@react-types/combobox@^3.12.1": version "3.12.1" resolved "https://registry.yarnpkg.com/@react-types/combobox/-/combobox-3.12.1.tgz#ab015d31c160aa0a21d696887ce81467c5996602" From 0cb7ed93e4ab94ac2785d668e3d13530e5b9e9f9 Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Wed, 4 Sep 2024 14:22:49 +0530 Subject: [PATCH 044/292] ref added for keydown (#717) * ref addded for keydown * enter key changes * tooltip changes * ishover state * theme fix * removal of handleKeydown * format fix --- .../ConnectionModal/ConnectionModal.tsx | 124 ++++++++++++------ .../Deduplication/index.tsx | 4 +- .../EntityExtractionSetting.tsx | 2 +- .../Popups/GraphEnhancementDialog/index.tsx | 2 +- .../src/components/UI/ButtonWithToolTip.tsx | 15 ++- .../src/components/UI/IconButtonToolTip.tsx | 12 +- frontend/src/context/ThemeWrapper.tsx | 26 ++-- 7 files changed, 121 insertions(+), 64 deletions(-) diff --git a/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx b/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx index ab9fe2399..8274e626a 100644 --- a/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx +++ b/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx @@ -1,5 +1,5 @@ import { Button, Dialog, TextInput, Dropdown, Banner, Dropzone, Typography, TextLink, Flex } from '@neo4j-ndl/react'; -import { useCallback, useEffect, useMemo, useState } from 'react'; +import React, { useCallback, useEffect, useMemo, useState, useRef } from 'react'; import connectAPI from '../../../services/ConnectAPI'; import { useCredentials } from '../../../context/UserCredentials'; import { useSearchParams } from 'react-router-dom'; @@ -46,6 +46,11 @@ export default function ConnectionModal({ const [searchParams, setSearchParams] = useSearchParams(); const [userDbVectorIndex, setUserDbVectorIndex] = useState(initialuserdbvectorindex ?? undefined); const [vectorIndexLoading, setVectorIndexLoading] = useState(false); + const connectRef = useRef(null); + const uriRef = useRef(null); + const databaseRef = useRef(null); + const userNameRef = useRef(null); + const passwordRef = useRef(null); useEffect(() => { if (searchParams.has('connectURL')) { @@ -274,6 +279,24 @@ export default function ConnectionModal({ setMessage({ type: 'unknown', content: '' }); }, []); + const handleKeyPress = (e: React.KeyboardEvent, nextRef?: React.RefObject) => { + if (e.code === 'Enter') { + e.preventDefault(); + // @ts-ignore + const { form } = e.target; + if (form) { + const index = Array.prototype.indexOf.call(form, e.target); + if (index + 1 < form.elements.length) { + form.elements[index + 1].focus(); + } else { + submitConnection(); + } + } else { + nextRef?.current?.focus(); + } + } + }; + const isDisabled = useMemo(() => !username || !URI || !password, [username, URI, password]); return ( @@ -348,6 +371,7 @@ export default function ConnectionModal({ />
setURI(e.target.value)} onPaste={(e) => handleHostPasteChange(e)} aria-label='Connection URI' + onKeyDown={(e) => handleKeyPress(e, databaseRef)} />
- setDatabase(e.target.value)} - className='w-full' - /> -
-
- setUsername(e.target.value)} - /> -
-
- setPassword(e.target.value)} - /> +
+ setDatabase(e.target.value)} + className='w-full' + onKeyDown={handleKeyPress} + /> +
+
+ setUsername(e.target.value)} + onKeyDown={handleKeyPress} + /> +
+
+ setPassword(e.target.value)} + onKeyDown={handleKeyPress} + /> +
-
+ - diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx index 36fcff3d1..f5a021e30 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx @@ -80,12 +80,12 @@ export default function DeduplicationTab() { const onRemove = (nodeid: string, similarNodeId: string) => { setDuplicateNodes((prev) => { return prev.map((d) => - d.e.elementId === nodeid + (d.e.elementId === nodeid ? { ...d, similar: d.similar.filter((n) => n.elementId != similarNodeId), } - : d + : d) ); }); }; diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/EnitityExtraction/EntityExtractionSetting.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/EnitityExtraction/EntityExtractionSetting.tsx index 37f283d2a..5bbd4607a 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/EnitityExtraction/EntityExtractionSetting.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/EnitityExtraction/EntityExtractionSetting.tsx @@ -312,7 +312,7 @@ export default function EntityExtractionSetting({ type='creatable' /> - + { + const [isHovered, setIsHovered] = useState(false); return ( - + - - {text} - + {isHovered && ( + + {text} + + )} ); }; diff --git a/frontend/src/components/UI/IconButtonToolTip.tsx b/frontend/src/components/UI/IconButtonToolTip.tsx index 62f438005..9622fd8e2 100644 --- a/frontend/src/components/UI/IconButtonToolTip.tsx +++ b/frontend/src/components/UI/IconButtonToolTip.tsx @@ -1,4 +1,5 @@ import { IconButton, Tip } from '@neo4j-ndl/react'; +import { useState } from 'react'; const IconButtonWithToolTip = ({ text, @@ -21,6 +22,7 @@ const IconButtonWithToolTip = ({ placement?: 'bottom' | 'top' | 'right' | 'left'; disabled?: boolean; }) => { + const [isHovered, setIsHovered] = useState(false); return ( @@ -31,13 +33,17 @@ const IconButtonWithToolTip = ({ grouped={grouped} onClick={onClick} disabled={disabled} + onMouseEnter={() => setIsHovered(true)} + onMouseLeave={() => setIsHovered(false)} > {children} - - {text} - + {isHovered && ( + + {text} + + )} ); }; diff --git a/frontend/src/context/ThemeWrapper.tsx b/frontend/src/context/ThemeWrapper.tsx index 110e8638b..963cbe3b8 100644 --- a/frontend/src/context/ThemeWrapper.tsx +++ b/frontend/src/context/ThemeWrapper.tsx @@ -1,36 +1,39 @@ -import { ReactNode, createContext, useMemo, useState } from 'react'; +import { ReactNode, createContext, useMemo, useState, useEffect } from 'react'; import { NeedleThemeProvider, useMediaQuery } from '@neo4j-ndl/react'; - export const ThemeWrapperContext = createContext({ toggleColorMode: () => {}, colorMode: localStorage.getItem('mode') as 'light' | 'dark', }); - interface ThemeWrapperProps { children: ReactNode; } const ThemeWrapper = ({ children }: ThemeWrapperProps) => { const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)'); - // @ts-ignore - const defaultMode: 'light' | 'dark' = localStorage.getItem('mode'); - const [mode, setMode] = useState<'light' | 'dark'>(prefersDarkMode ? 'dark' : defaultMode ?? 'light'); - const [usingPreferredMode, setUsingPreferredMode] = useState(true); + const defaultMode = localStorage.getItem('mode') as 'light' | 'dark'; + const [mode, setMode] = useState<'light' | 'dark'>(defaultMode ?? (prefersDarkMode ? 'dark' : 'light')); + const [usingPreferredMode, setUsingPreferredMode] = useState(!defaultMode); + + useEffect(() => { + // Ensure the body class is updated on initial load + themeBodyInjection(mode); + }, [mode]); const themeWrapperUtils = useMemo( () => ({ colorMode: mode, toggleColorMode: () => { setMode((prevMode) => { + const newMode = prevMode === 'light' ? 'dark' : 'light'; setUsingPreferredMode(false); - localStorage.setItem('mode', prevMode === 'light' ? 'dark' : 'light'); - themeBodyInjection(prevMode); - return prevMode === 'light' ? 'dark' : 'light'; + localStorage.setItem('mode', newMode); + themeBodyInjection(newMode); + return newMode; }); }, }), [mode] ); const themeBodyInjection = (mode: string) => { - if (mode === 'light') { + if (mode === 'dark') { document.body.classList.add('ndl-theme-dark'); } else { document.body.classList.remove('ndl-theme-dark'); @@ -40,7 +43,6 @@ const ThemeWrapper = ({ children }: ThemeWrapperProps) => { if (usingPreferredMode) { prefersDarkMode ? themeBodyInjection('light') : themeBodyInjection('dark'); } - return ( From 18b0093f8bde824b7fe6d8d1d21c91b0d24a72b5 Mon Sep 17 00:00:00 2001 From: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Date: Wed, 4 Sep 2024 14:24:32 +0530 Subject: [PATCH 045/292] Remove total_pages propert. It is not used in DB. (#714) Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> --- backend/score.py | 2 -- backend/src/document_sources/gcs_bucket.py | 1 - backend/src/document_sources/local_file.py | 16 ++++++++-------- backend/src/entities/source_node.py | 1 - backend/src/graphDB_dataAccess.py | 9 +++------ backend/src/main.py | 8 +------- docs/backend/backend_docs.adoc | 1 - 7 files changed, 12 insertions(+), 26 deletions(-) diff --git a/backend/score.py b/backend/score.py index 08ea9a6b2..6d2cd79a1 100644 --- a/backend/score.py +++ b/backend/score.py @@ -445,7 +445,6 @@ async def generate(): 'relationshipCount':result[0]['relationshipCount'], 'model':result[0]['model'], 'total_chunks':result[0]['total_chunks'], - 'total_pages':result[0]['total_pages'], 'fileSize':result[0]['fileSize'], 'processed_chunk':result[0]['processed_chunk'], 'fileSource':result[0]['fileSource'] @@ -504,7 +503,6 @@ async def get_document_status(file_name, url, userName, password, database): 'relationshipCount':result[0]['relationshipCount'], 'model':result[0]['model'], 'total_chunks':result[0]['total_chunks'], - 'total_pages':result[0]['total_pages'], 'fileSize':result[0]['fileSize'], 'processed_chunk':result[0]['processed_chunk'], 'fileSource':result[0]['fileSource'] diff --git a/backend/src/document_sources/gcs_bucket.py b/backend/src/document_sources/gcs_bucket.py index 4a5909fc4..91830f591 100644 --- a/backend/src/document_sources/gcs_bucket.py +++ b/backend/src/document_sources/gcs_bucket.py @@ -122,7 +122,6 @@ def merge_file_gcs(bucket_name, original_file_name: str, folder_name_sha1_hashed blob.upload_from_file(file_io) # pdf_reader = PdfReader(file_io) file_size = len(merged_file) - # total_pages = len(pdf_reader.pages) return file_size except Exception as e: diff --git a/backend/src/document_sources/local_file.py b/backend/src/document_sources/local_file.py index 9fb31649f..ed46210f4 100644 --- a/backend/src/document_sources/local_file.py +++ b/backend/src/document_sources/local_file.py @@ -56,19 +56,19 @@ def get_pages_with_page_numbers(unstructured_pages): if page.metadata['page_number']==page_number: page_content += page.page_content metadata = {'source':page.metadata['source'],'page_number':page_number, 'filename':page.metadata['filename'], - 'filetype':page.metadata['filetype'], 'total_pages':unstructured_pages[-1].metadata['page_number']} + 'filetype':page.metadata['filetype']} if page.metadata['page_number']>page_number: page_number+=1 - if not metadata: - metadata = {'total_pages':unstructured_pages[-1].metadata['page_number']} - pages.append(Document(page_content = page_content, metadata=metadata)) + # if not metadata: + # metadata = {'total_pages':unstructured_pages[-1].metadata['page_number']} + pages.append(Document(page_content = page_content)) page_content='' if page == unstructured_pages[-1]: - if not metadata: - metadata = {'total_pages':unstructured_pages[-1].metadata['page_number']} - pages.append(Document(page_content = page_content, metadata=metadata)) + # if not metadata: + # metadata = {'total_pages':unstructured_pages[-1].metadata['page_number']} + pages.append(Document(page_content = page_content)) elif page.metadata['category']=='PageBreak' and page!=unstructured_pages[0]: page_number+=1 @@ -80,7 +80,7 @@ def get_pages_with_page_numbers(unstructured_pages): page_content += page.page_content metadata_with_custom_page_number = {'source':page.metadata['source'], 'page_number':1, 'filename':page.metadata['filename'], - 'filetype':page.metadata['filetype'], 'total_pages':1} + 'filetype':page.metadata['filetype']} if page == unstructured_pages[-1]: pages.append(Document(page_content = page_content, metadata=metadata_with_custom_page_number)) return pages \ No newline at end of file diff --git a/backend/src/entities/source_node.py b/backend/src/entities/source_node.py index 1a1c70487..a162b6d04 100644 --- a/backend/src/entities/source_node.py +++ b/backend/src/entities/source_node.py @@ -18,7 +18,6 @@ class sourceNode: updated_at:datetime=None processing_time:float=None error_message:str=None - total_pages:int=None total_chunks:int=None language:str=None is_cancelled:bool=None diff --git a/backend/src/graphDB_dataAccess.py b/backend/src/graphDB_dataAccess.py index c1eaaa190..36a9a2925 100644 --- a/backend/src/graphDB_dataAccess.py +++ b/backend/src/graphDB_dataAccess.py @@ -37,14 +37,14 @@ def create_source_node(self, obj_source_node:sourceNode): d.processingTime = $pt, d.errorMessage = $e_message, d.nodeCount= $n_count, d.relationshipCount = $r_count, d.model= $model, d.gcsBucket=$gcs_bucket, d.gcsBucketFolder= $gcs_bucket_folder, d.language= $language,d.gcsProjectId= $gcs_project_id, - d.is_cancelled=False, d.total_chunks=0, d.processed_chunk=0, d.total_pages=$total_pages, + d.is_cancelled=False, d.total_chunks=0, d.processed_chunk=0, d.access_token=$access_token""", {"fn":obj_source_node.file_name, "fs":obj_source_node.file_size, "ft":obj_source_node.file_type, "st":job_status, "url":obj_source_node.url, "awsacc_key_id":obj_source_node.awsAccessKeyId, "f_source":obj_source_node.file_source, "c_at":obj_source_node.created_at, "u_at":obj_source_node.created_at, "pt":0, "e_message":'', "n_count":0, "r_count":0, "model":obj_source_node.model, "gcs_bucket": obj_source_node.gcsBucket, "gcs_bucket_folder": obj_source_node.gcsBucketFolder, - "language":obj_source_node.language, "gcs_project_id":obj_source_node.gcsProjectId, "total_pages": obj_source_node.total_pages, + "language":obj_source_node.language, "gcs_project_id":obj_source_node.gcsProjectId, "access_token":obj_source_node.access_token}) except Exception as e: error_message = str(e) @@ -80,9 +80,6 @@ def update_source_node(self, obj_source_node:sourceNode): if obj_source_node.model is not None and obj_source_node.model != '': params['model'] = obj_source_node.model - if obj_source_node.total_pages is not None and obj_source_node.total_pages != 0: - params['total_pages'] = obj_source_node.total_pages - if obj_source_node.total_chunks is not None and obj_source_node.total_chunks != 0: params['total_chunks'] = obj_source_node.total_chunks @@ -190,7 +187,7 @@ def get_current_status_document_node(self, file_name): query = """ MATCH(d:Document {fileName : $file_name}) RETURN d.status AS Status , d.processingTime AS processingTime, d.nodeCount AS nodeCount, d.model as model, d.relationshipCount as relationshipCount, - d.total_pages AS total_pages, d.total_chunks AS total_chunks , d.fileSize as fileSize, + d.total_chunks AS total_chunks , d.fileSize as fileSize, d.is_cancelled as is_cancelled, d.processed_chunk as processed_chunk, d.fileSource as fileSource """ param = {"file_name" : file_name} diff --git a/backend/src/main.py b/backend/src/main.py index 3a88f1eb3..caf5d58dc 100644 --- a/backend/src/main.py +++ b/backend/src/main.py @@ -52,7 +52,6 @@ def create_source_node_graph_url_s3(graph, model, source_url, aws_access_key_id, obj_source_node.file_type = 'pdf' obj_source_node.file_size = file_info['file_size_bytes'] obj_source_node.file_source = source_type - obj_source_node.total_pages = 'N/A' obj_source_node.model = model obj_source_node.url = str(source_url+file_name) obj_source_node.awsAccessKeyId = aws_access_key_id @@ -82,7 +81,6 @@ def create_source_node_graph_url_gcs(graph, model, gcs_project_id, gcs_bucket_na obj_source_node.file_size = file_metadata['fileSize'] obj_source_node.url = file_metadata['url'] obj_source_node.file_source = source_type - obj_source_node.total_pages = 'N/A' obj_source_node.model = model obj_source_node.file_type = 'pdf' obj_source_node.gcsBucket = gcs_bucket_name @@ -116,7 +114,6 @@ def create_source_node_graph_web_url(graph, model, source_url, source_type): obj_source_node.file_type = 'text' obj_source_node.file_source = source_type obj_source_node.model = model - obj_source_node.total_pages = 1 obj_source_node.url = urllib.parse.unquote(source_url) obj_source_node.created_at = datetime.now() obj_source_node.file_name = pages[0].metadata['title'] @@ -139,7 +136,6 @@ def create_source_node_graph_url_youtube(graph, model, source_url, source_type): obj_source_node.file_type = 'text' obj_source_node.file_source = source_type obj_source_node.model = model - obj_source_node.total_pages = 1 obj_source_node.url = youtube_url obj_source_node.created_at = datetime.now() match = re.search(r'(?:v=)([0-9A-Za-z_-]{11})\s*',obj_source_node.url) @@ -177,7 +173,6 @@ def create_source_node_graph_url_wikipedia(graph, model, wiki_query, source_type obj_source_node.file_type = 'text' obj_source_node.file_source = source_type obj_source_node.file_size = sys.getsizeof(pages[0].page_content) - obj_source_node.total_pages = len(pages) obj_source_node.model = model obj_source_node.url = urllib.parse.unquote(pages[0].metadata['source']) obj_source_node.created_at = datetime.now() @@ -289,8 +284,7 @@ def processing_source(uri, userName, password, database, model, file_name, pages status = "Processing" obj_source_node.file_name = file_name obj_source_node.status = status - obj_source_node.total_chunks = total_chunks - obj_source_node.total_pages = len(pages) + obj_source_node.total_chunks = len(chunks) obj_source_node.model = model if retry_condition == START_FROM_LAST_PROCESSED_POSITION: node_count = result[0]['nodeCount'] diff --git a/docs/backend/backend_docs.adoc b/docs/backend/backend_docs.adoc index a2887d6f9..91b39260c 100644 --- a/docs/backend/backend_docs.adoc +++ b/docs/backend/backend_docs.adoc @@ -580,7 +580,6 @@ The API provides a continuous update on the extraction status of a specified fil "relationshipCount": 0, "model": "OpenAI GPT 3.5", "total_chunks": 3, - "total_pages": 1, "fileSize": 92373, "processed_chunk": 0 } From eb48190fcf2f99f18e0f167e21dc15dd060d0cea Mon Sep 17 00:00:00 2001 From: aashipandya <156318202+aashipandya@users.noreply.github.com> Date: Wed, 4 Sep 2024 17:16:03 +0530 Subject: [PATCH 046/292] Update main.py --- backend/src/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/main.py b/backend/src/main.py index caf5d58dc..5eb8fd59d 100644 --- a/backend/src/main.py +++ b/backend/src/main.py @@ -284,7 +284,7 @@ def processing_source(uri, userName, password, database, model, file_name, pages status = "Processing" obj_source_node.file_name = file_name obj_source_node.status = status - obj_source_node.total_chunks = len(chunks) + obj_source_node.total_chunks = total_chunks obj_source_node.model = model if retry_condition == START_FROM_LAST_PROCESSED_POSITION: node_count = result[0]['nodeCount'] @@ -623,4 +623,4 @@ def set_status_retry(graph, file_name, retry_condition): obj_source_node.node_count=0 obj_source_node.relationship_count=0 logging.info(obj_source_node) - graphDb_data_Access.update_source_node(obj_source_node) \ No newline at end of file + graphDb_data_Access.update_source_node(obj_source_node) From 5ff0014155888956778c0836eb183696d42f846d Mon Sep 17 00:00:00 2001 From: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Date: Thu, 5 Sep 2024 09:51:14 +0000 Subject: [PATCH 047/292] Add print statement for document status --- backend/score.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/backend/score.py b/backend/score.py index 6d2cd79a1..15b381e83 100644 --- a/backend/score.py +++ b/backend/score.py @@ -437,7 +437,8 @@ async def generate(): graph = create_graph_database_connection(uri, userName, decoded_password, database) graphDb_data_Access = graphDBdataAccess(graph) result = graphDb_data_Access.get_current_status_document_node(file_name) - if result is not None: + print(f'Result of document status in SSE : {result}') + if len(result) > 0: status = json.dumps({'fileName':file_name, 'status':result[0]['Status'], 'processingTime':result[0]['processingTime'], @@ -495,7 +496,7 @@ async def get_document_status(file_name, url, userName, password, database): graph = create_graph_database_connection(uri, userName, decoded_password, database) graphDb_data_Access = graphDBdataAccess(graph) result = graphDb_data_Access.get_current_status_document_node(file_name) - if result is not None: + if len(result) > 0: status = {'fileName':file_name, 'status':result[0]['Status'], 'processingTime':result[0]['processingTime'], @@ -509,6 +510,7 @@ async def get_document_status(file_name, url, userName, password, database): } else: status = {'fileName':file_name, 'status':'Failed'} + print(f'Result of document status in refresh : {result}') return create_api_response('Success',message="",file_name=status) except Exception as e: message=f"Unable to get the document status" From 8215abd1a32ab2302024c6473d0e173510512b45 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Thu, 5 Sep 2024 11:40:13 +0000 Subject: [PATCH 048/292] refactored qa integration --- backend/src/QA_integration.py | 342 ---------------- backend/src/QA_integration_new.py | 659 ++++++++++++++++++------------ backend/src/QA_optimization.py | 217 ---------- backend/src/shared/constants.py | 3 + 4 files changed, 408 insertions(+), 813 deletions(-) delete mode 100644 backend/src/QA_integration.py delete mode 100644 backend/src/QA_optimization.py diff --git a/backend/src/QA_integration.py b/backend/src/QA_integration.py deleted file mode 100644 index 6a70c3ec0..000000000 --- a/backend/src/QA_integration.py +++ /dev/null @@ -1,342 +0,0 @@ -from langchain_community.vectorstores.neo4j_vector import Neo4jVector -from langchain.chains import GraphCypherQAChain -from langchain.graphs import Neo4jGraph -import os - -from dotenv import load_dotenv -from langchain.chains import RetrievalQA -from langchain.chains import RetrievalQAWithSourcesChain -from langchain_openai import ChatOpenAI -from langchain_openai import OpenAIEmbeddings -from langchain_google_vertexai import VertexAIEmbeddings -from langchain_google_vertexai import ChatVertexAI -from langchain_google_vertexai import HarmBlockThreshold, HarmCategory -import logging -from langchain_community.chat_message_histories import Neo4jChatMessageHistory -from langchain_community.embeddings.sentence_transformer import SentenceTransformerEmbeddings -from src.shared.common_fn import load_embedding_model -import re -from typing import Any -from datetime import datetime -import time - -load_dotenv() - -openai_api_key = os.environ.get('OPENAI_API_KEY') - -EMBEDDING_MODEL = os.getenv('EMBEDDING_MODEL') -EMBEDDING_FUNCTION , _ = load_embedding_model(EMBEDDING_MODEL) -CHAT_MAX_TOKENS = 1000 - - -# RETRIEVAL_QUERY = """ -# WITH node, score, apoc.text.join([ (node)-[:__HAS_ENTITY__]->(e) | head(labels(e)) + ": "+ e.id],", ") as entities -# MATCH (node)-[:__PART_OF__]->(d:Document) -# WITH d, apoc.text.join(collect(node.text + "\n" + entities),"\n----\n") as text, avg(score) as score -# RETURN text, score, {source: COALESCE(CASE WHEN d.url CONTAINS "None" THEN d.fileName ELSE d.url END, d.fileName)} as metadata -# """ - -RETRIEVAL_QUERY = """ -WITH node as chunk, score -MATCH (chunk)-[:__PART_OF__]->(d:__Document__) -CALL { WITH chunk -MATCH (chunk)-[:__HAS_ENTITY__]->(e) -MATCH path=(e)(()-[rels:!__HAS_ENTITY__&!__PART_OF__]-()){0,3}(:!__Chunk__&!__Document__) -UNWIND rels as r -RETURN collect(distinct r) as rels -} -WITH d, collect(distinct chunk) as chunks, avg(score) as score, apoc.coll.toSet(apoc.coll.flatten(collect(rels))) as rels -WITH d, score, -[c in chunks | c.text] as texts, -[r in rels | coalesce(apoc.coll.removeAll(labels(startNode(r)),['__Entity__'])[0],"") +":"+ startNode(r).id + " "+ type(r) + " " + coalesce(apoc.coll.removeAll(labels(endNode(r)),['__Entity__'])[0],"") +":" + endNode(r).id] as entities -WITH d, score, -apoc.text.join(texts,"\n----\n") + -apoc.text.join(entities,"\n") -as text, entities -RETURN text, score, {source: COALESCE(CASE WHEN d.url CONTAINS "None" THEN d.fileName ELSE d.url END, d.fileName), entities:entities} as metadata -""" - -FINAL_PROMPT = """ -You are an AI-powered question-answering agent tasked with providing accurate and direct responses to user queries. Utilize information from the chat history, current user input, and Relevant Information effectively. - -Response Requirements: -- Deliver concise and direct answers to the user's query without headers unless requested. -- Acknowledge and utilize relevant previous interactions based on the chat history summary. -- Respond to initial greetings appropriately, but avoid including a greeting in subsequent responses unless the chat is restarted or significantly paused. -- For non-general questions, strive to provide answers using chat history and Relevant Information ONLY do not Hallucinate. -- Clearly state if an answer is unknown; avoid speculating. - -Instructions: -- Prioritize directly answering the User Input: {question}. -- Use the Chat History Summary: {chat_summary} to provide context-aware responses. -- Refer to Relevant Information: {vector_result} only if it directly relates to the query. -- Cite sources clearly when using Relevant Information in your response [Sources: {sources}] without fail. The Source must be printed only at the last in the format [Source: source1,source2] . Duplicate sources should be removed. -Ensure that answers are straightforward and context-aware, focusing on being relevant and concise. -""" - -def get_llm(model: str,max_tokens=1000) -> Any: - """Retrieve the specified language model based on the model name.""" - - model_versions = { - "openai-gpt-3.5": "gpt-3.5-turbo-16k", - "gemini-1.0-pro": "gemini-1.0-pro-001", - "gemini-1.5-pro": "gemini-1.5-pro-preview-0409", - "openai-gpt-4": "gpt-4-0125-preview", - "diffbot" : "gpt-4-0125-preview", - "openai-gpt-4o":"gpt-4o", - "openai-gpt-4o-mini": "gpt-4o-mini", - } - if model in model_versions: - model_version = model_versions[model] - logging.info(f"Chat Model: {model}, Model Version: {model_version}") - - if "Gemini" in model: - llm = ChatVertexAI( - model_name=model_version, - convert_system_message_to_human=True, - max_tokens=max_tokens, - temperature=0, - safety_settings={ - HarmCategory.HARM_CATEGORY_UNSPECIFIED: HarmBlockThreshold.BLOCK_NONE, - HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: HarmBlockThreshold.BLOCK_NONE, - HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_NONE, - HarmCategory.HARM_CATEGORY_HARASSMENT: HarmBlockThreshold.BLOCK_NONE, - HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: HarmBlockThreshold.BLOCK_NONE - } - ) - else: - llm = ChatOpenAI(model=model_version, temperature=0,max_tokens=max_tokens) - - return llm,model_version - - else: - logging.error(f"Unsupported model: {model}") - return None,None - -def vector_embed_results(qa,question): - vector_res={} - try: - result = qa({"query": question}) - vector_res['result']=result.get("result") - - sources = set() - entities = set() - for document in result["source_documents"]: - sources.add(document.metadata["source"]) - for entiti in document.metadata["entities"]: - entities.add(entiti) - vector_res['source']=list(sources) - vector_res['entities'] = list(entities) - if len( vector_res['entities']) > 5: - vector_res['entities'] = vector_res['entities'][:5] - - # list_source_docs=[] - # for i in result["source_documents"]: - # list_source_docs.append(i.metadata['source']) - # vector_res['source']=list_source_docs - - # result = qa({"question":question},return_only_outputs=True) - # vector_res['result'] = result.get("answer") - # vector_res["source"] = result.get("sources") - except Exception as e: - error_message = str(e) - logging.exception(f'Exception in vector embedding in QA component:{error_message}') - # raise Exception(error_message) - - return vector_res - -def save_chat_history(history,user_message,ai_message): - try: - # history = Neo4jChatMessageHistory( - # graph=graph, - # session_id=session_id - # ) - history.add_user_message(user_message) - history.add_ai_message(ai_message) - logging.info(f'Successfully saved chat history') - except Exception as e: - error_message = str(e) - logging.exception(f'Exception in saving chat history:{error_message}') - -def get_chat_history(llm, history): - """Retrieves and summarizes the chat history for a given session.""" - - try: - # history = Neo4jChatMessageHistory( - # graph=graph, - # session_id=session_id - # ) - chat_history = history.messages - - if not chat_history: - return "" - - if len(chat_history) > 4: - chat_history = chat_history[-4:] - - condense_template = f""" - Given the following earlier conversation, summarize the chat history. - Make sure to include all relevant information. - Chat History: {chat_history} - """ - chat_summary = llm.predict(condense_template) - return chat_summary - - except Exception as e: - logging.exception(f"Exception in retrieving chat history: {e}") - return "" - -def clear_chat_history(graph, session_id): - - try: - logging.info(f"Clearing chat history for session ID: {session_id}") - history = Neo4jChatMessageHistory( - graph=graph, - session_id=session_id - ) - history.clear() - logging.info("Chat history cleared successfully") - - return { - "session_id": session_id, - "message": "The chat history is cleared", - "user": "chatbot" - } - except Exception as e: - logging.exception(f"Error occurred while clearing chat history for session ID {session_id}: {e}") - - -def extract_and_remove_source(message): - pattern = r'\[Source: ([^\]]+)\]' - match = re.search(pattern, message) - if match: - sources_string = match.group(1) - sources = [source.strip().strip("'") for source in sources_string.split(',')] - new_message = re.sub(pattern, '', message).strip() - response = { - "message" : new_message, - "sources" : sources - } - else: - response = { - "message" : message, - "sources" : [] - } - return response - -def clear_chat_history(graph,session_id): - history = Neo4jChatMessageHistory( - graph=graph, - session_id=session_id - ) - history.clear() - return { - "session_id": session_id, - "message": "The chat History is cleared", - "user": "chatbot" - } - -def QA_RAG(graph,model,question,session_id): - logging.info(f"QA_RAG called at {datetime.now()}") - # model = "Gemini Pro" - try: - qa_rag_start_time = time.time() - - - start_time = time.time() - neo_db = Neo4jVector.from_existing_index( - embedding=EMBEDDING_FUNCTION, - index_name="vector", - retrieval_query=RETRIEVAL_QUERY, - graph=graph - ) - - history = Neo4jChatMessageHistory( - graph=graph, - session_id=session_id - ) - - llm,model_version = get_llm(model=model,max_tokens=CHAT_MAX_TOKENS) - - qa = RetrievalQA.from_chain_type( - llm=llm, - chain_type="stuff", - retriever=neo_db.as_retriever(search_kwargs={'k': 3, "score_threshold": 0.7}), - return_source_documents=True - ) - # qa = RetrievalQAWithSourcesChain.from_chain_type( - # llm=llm, - # chain_type="stuff", - # retriever=neo_db.as_retriever(search_kwargs={'k': 3, "score_threshold": 0.7})) - - db_setup_time = time.time() - start_time - logging.info(f"DB Setup completed in {db_setup_time:.2f} seconds") - - start_time = time.time() - chat_summary = get_chat_history(llm,history) - chat_history_time = time.time() - start_time - logging.info(f"Chat history summarized in {chat_history_time:.2f} seconds") - # print(chat_summary) - - start_time = time.time() - vector_res = vector_embed_results(qa, question) - vector_time = time.time() - start_time - logging.info(f"Vector response obtained in {vector_time:.2f} seconds") - # print(vector_res) - - formatted_prompt = FINAL_PROMPT.format( - question=question, - chat_summary=chat_summary, - vector_result=vector_res.get('result', ''), - sources=vector_res.get('source', '') - ) - # print(formatted_prompt) - - start_time = time.time() - # llm = get_llm(model=model,embedding=False) - response = llm.predict(formatted_prompt) - predict_time = time.time() - start_time - logging.info(f"Response predicted in {predict_time:.2f} seconds") - - start_time = time.time() - ai_message = response - user_message = question - save_chat_history(history, user_message, ai_message) - chat_history_save = time.time() - start_time - logging.info(f"Chat History saved in {chat_history_save:.2f} seconds") - - response_data = extract_and_remove_source(response) - message = response_data["message"] - sources = response_data["sources"] - - print(f"message : {message}") - print(f"sources : {sources}") - total_call_time = time.time() - qa_rag_start_time - logging.info(f"Total Response time is {total_call_time:.2f} seconds") - return { - "session_id": session_id, - "message": message, - "info": { - "sources": sources, - "model":model_version, - "entities":vector_res["entities"] - }, - "user": "chatbot" - } - - except Exception as e: - logging.exception(f"Exception in QA component at {datetime.now()}: {str(e)}") - error_name = type(e).__name__ - return { - "session_id": session_id, - "message": "Something went wrong", - "info": { - "sources": [], - "error": f"{error_name} :- {str(e)}" - }, - "user": "chatbot"} - - - - - diff --git a/backend/src/QA_integration_new.py b/backend/src/QA_integration_new.py index eeac78c1e..6fe4907f1 100644 --- a/backend/src/QA_integration_new.py +++ b/backend/src/QA_integration_new.py @@ -1,5 +1,4 @@ from langchain_community.vectorstores.neo4j_vector import Neo4jVector -from langchain.graphs import Neo4jGraph import os from dotenv import load_dotenv import logging @@ -38,50 +37,178 @@ EMBEDDING_MODEL = os.getenv('EMBEDDING_MODEL') EMBEDDING_FUNCTION , _ = load_embedding_model(EMBEDDING_MODEL) - -def get_neo4j_retriever(graph, retrieval_query,document_names,mode,index_name="vector",keyword_index="keyword", search_k=CHAT_SEARCH_KWARG_K, score_threshold=CHAT_SEARCH_KWARG_SCORE_THRESHOLD): +def get_total_tokens(ai_response, llm): try: - if mode == "fulltext" or mode == "graph + vector + fulltext": - neo_db = Neo4jVector.from_existing_graph( - embedding=EMBEDDING_FUNCTION, - index_name=index_name, - retrieval_query=retrieval_query, - graph=graph, - search_type="hybrid", - node_label="Chunk", - embedding_node_property="embedding", - text_node_properties=["text"], - keyword_index_name=keyword_index - ) - # neo_db = Neo4jVector.from_existing_index( - # embedding=EMBEDDING_FUNCTION, - # index_name=index_name, - # retrieval_query=retrieval_query, - # graph=graph, - # search_type="hybrid", - # keyword_index_name=keyword_index - # ) - logging.info(f"Successfully retrieved Neo4jVector index '{index_name}' and keyword index '{keyword_index}'") + if isinstance(llm, (ChatOpenAI, AzureChatOpenAI, ChatFireworks, ChatGroq)): + total_tokens = ai_response.response_metadata.get('token_usage', {}).get('total_tokens', 0) + + elif isinstance(llm, ChatVertexAI): + total_tokens = ai_response.response_metadata.get('usage_metadata', {}).get('prompt_token_count', 0) + + elif isinstance(llm, ChatBedrock): + total_tokens = ai_response.response_metadata.get('usage', {}).get('total_tokens', 0) + + elif isinstance(llm, ChatAnthropic): + input_tokens = int(ai_response.response_metadata.get('usage', {}).get('input_tokens', 0)) + output_tokens = int(ai_response.response_metadata.get('usage', {}).get('output_tokens', 0)) + total_tokens = input_tokens + output_tokens + + elif isinstance(llm, ChatOllama): + total_tokens = ai_response.response_metadata.get("prompt_eval_count", 0) + else: - neo_db = Neo4jVector.from_existing_index( - embedding=EMBEDDING_FUNCTION, - index_name=index_name, - retrieval_query=retrieval_query, - graph=graph + logging.warning(f"Unrecognized language model: {type(llm)}. Returning 0 tokens.") + total_tokens = 0 + + except Exception as e: + logging.error(f"Error retrieving total tokens: {e}") + total_tokens = 0 + + return total_tokens + +def clear_chat_history(graph, session_id): + try: + history = Neo4jChatMessageHistory( + graph=graph, + session_id=session_id + ) + + history.clear() + + return { + "session_id": session_id, + "message": "The chat history has been cleared.", + "user": "chatbot" + } + + except Exception as e: + logging.error(f"Error clearing chat history for session {session_id}: {e}") + return { + "session_id": session_id, + "message": "Failed to clear chat history.", + "user": "chatbot" + } + +def get_sources_and_chunks(sources_used, docs): + chunkdetails_list = [] + + sources_used_set = set(sources_used) + + for doc in docs: + try: + source = doc.metadata.get("source") + chunkdetails = doc.metadata.get("chunkdetails", []) + + if source in sources_used_set: + formatted_chunkdetails = [ + {**chunkdetail, "score": round(chunkdetail.get("score", 0), 4)} + for chunkdetail in chunkdetails + ] + chunkdetails_list.extend(formatted_chunkdetails) + + except Exception as e: + logging.error(f"Error processing document: {e}", exc_info=True) + + result = { + 'sources': sources_used, + 'chunkdetails': chunkdetails_list + } + return result + + +def get_rag_chain(llm, system_template=CHAT_SYSTEM_TEMPLATE): + try: + question_answering_prompt = ChatPromptTemplate.from_messages( + [ + ("system", system_template), + MessagesPlaceholder(variable_name="messages"), + ( + "human", + "User question: {input}" + ), + ] + ) + + question_answering_chain = question_answering_prompt | llm + + return question_answering_chain + + except Exception as e: + logging.error(f"Error creating RAG chain: {e}") + raise + +def format_documents(documents, model): + prompt_token_cutoff = 4 + for model_names, value in CHAT_TOKEN_CUT_OFF.items(): + if model in model_names: + prompt_token_cutoff = value + break + + sorted_documents = sorted(documents, key=lambda doc: doc.state.get("query_similarity_score", 0), reverse=True) + sorted_documents = sorted_documents[:prompt_token_cutoff] + + formatted_docs = [] + sources = set() + + for doc in sorted_documents: + try: + source = doc.metadata.get('source', 'unknown') + sources.add(source) + + formatted_doc = ( + "Document start\n" + f"This Document belongs to the source {source}\n" + f"Content: {doc.page_content}\n" + "Document end\n" ) - logging.info(f"Successfully retrieved Neo4jVector index '{index_name}'") - document_names= list(map(str.strip, json.loads(document_names))) - if document_names: - retriever = neo_db.as_retriever(search_type="similarity_score_threshold",search_kwargs={'k': search_k, "score_threshold": score_threshold,'filter':{'fileName': {'$in': document_names}}}) - logging.info(f"Successfully created retriever for index '{index_name}' with search_k={search_k}, score_threshold={score_threshold} for documents {document_names}") - else: - retriever = neo_db.as_retriever(search_type="similarity_score_threshold",search_kwargs={'k': search_k, "score_threshold": score_threshold}) - logging.info(f"Successfully created retriever for index '{index_name}' with search_k={search_k}, score_threshold={score_threshold}") - return retriever + formatted_docs.append(formatted_doc) + + except Exception as e: + logging.error(f"Error formatting document: {e}") + + return "\n\n".join(formatted_docs), sources + +def process_documents(docs, question, messages, llm, model): + start_time = time.time() + + try: + formatted_docs, sources = format_documents(docs, model) + + rag_chain = get_rag_chain(llm=llm) + + ai_response = rag_chain.invoke({ + "messages": messages[:-1], + "context": formatted_docs, + "input": question + }) + + result = get_sources_and_chunks(sources, docs) + content = ai_response.content + total_tokens = get_total_tokens(ai_response, llm) + + predict_time = time.time() - start_time + logging.info(f"Final response predicted in {predict_time:.2f} seconds") + except Exception as e: - logging.error(f"Error retrieving Neo4jVector index '{index_name}' or creating retriever: {e}") - raise Exception("An error occurred while retrieving the Neo4jVector index '{index_name}' or creating the retriever. Please drop and create a new vector index: {e}") from e + logging.error(f"Error processing documents: {e}") + raise + return content, result, total_tokens + +def retrieve_documents(doc_retriever, messages): + + start_time = time.time() + try: + docs = doc_retriever.invoke({"messages": messages}) + doc_retrieval_time = time.time() - start_time + logging.info(f"Documents retrieved in {doc_retrieval_time:.2f} seconds") + + except Exception as e: + logging.error(f"Error retrieving documents: {e}") + raise + + return docs + def create_document_retriever_chain(llm, retriever): try: logging.info("Starting to create document retriever chain") @@ -124,182 +251,176 @@ def create_document_retriever_chain(llm, retriever): logging.error(f"Error creating document retriever chain: {e}", exc_info=True) raise - -def create_neo4j_chat_message_history(graph, session_id): - """ - Creates and returns a Neo4jChatMessageHistory instance. - - """ +def initialize_neo4j_vector(graph, chat_mode_settings): try: + mode = chat_mode_settings.get('mode', 'undefined') + retrieval_query = chat_mode_settings.get("retrieval_query") + index_name = chat_mode_settings.get("index_name") + keyword_index = chat_mode_settings.get("keyword_index", "") - history = Neo4jChatMessageHistory( - graph=graph, - session_id=session_id - ) - return history + if not retrieval_query or not index_name: + raise ValueError("Required settings 'retrieval_query' or 'index_name' are missing.") - except Exception as e: - logging.error(f"Error creating Neo4jChatMessageHistory: {e}") - raise - -def format_documents(documents,model): - prompt_token_cutoff = 4 - for models,value in CHAT_TOKEN_CUT_OFF.items(): - if model in models: - prompt_token_cutoff = value - - sorted_documents = sorted(documents, key=lambda doc: doc.state["query_similarity_score"], reverse=True) - sorted_documents = sorted_documents[:prompt_token_cutoff] - - formatted_docs = [] - sources = set() + if mode in ["fulltext", "graph+vector+fulltext"]: + neo_db = Neo4jVector.from_existing_graph( + embedding=EMBEDDING_FUNCTION, + index_name=index_name, + retrieval_query=retrieval_query, + graph=graph, + search_type="hybrid", + node_label="Chunk", + embedding_node_property="embedding", + text_node_properties=["text"], + keyword_index_name=keyword_index + ) + logging.info(f"Successfully retrieved Neo4jVector Fulltext index '{index_name}' and keyword index '{keyword_index}'") + else: + neo_db = Neo4jVector.from_existing_index( + embedding=EMBEDDING_FUNCTION, + index_name=index_name, + retrieval_query=retrieval_query, + graph=graph + ) + logging.info(f"Successfully retrieved Neo4jVector index '{index_name}'") - for doc in sorted_documents: - source = doc.metadata['source'] - sources.add(source) - - formatted_doc = ( - "Document start\n" - f"This Document belongs to the source {source}\n" - f"Content: {doc.page_content}\n" - "Document end\n" + except Exception as e: + logging.error(f"Error retrieving Neo4jVector index : {e}") + raise + return neo_db + +def create_retriever(neo_db, document_names, search_k, score_threshold): + if document_names: + retriever = neo_db.as_retriever( + search_type="similarity_score_threshold", + search_kwargs={ + 'k': search_k, + 'score_threshold': score_threshold, + 'filter': {'fileName': {'$in': document_names}} + } + ) + logging.info(f"Successfully created retriever with search_k={search_k}, score_threshold={score_threshold} for documents {document_names}") + else: + retriever = neo_db.as_retriever( + search_type="similarity_score_threshold", + search_kwargs={'k': search_k, 'score_threshold': score_threshold} ) - formatted_docs.append(formatted_doc) + logging.info(f"Successfully created retriever with search_k={search_k}, score_threshold={score_threshold}") + return retriever - return "\n\n".join(formatted_docs), sources +def get_neo4j_retriever(graph, document_names,chat_mode_settings, search_k=CHAT_SEARCH_KWARG_K, score_threshold=CHAT_SEARCH_KWARG_SCORE_THRESHOLD): + try: -def get_rag_chain(llm,system_template=CHAT_SYSTEM_TEMPLATE): - question_answering_prompt = ChatPromptTemplate.from_messages( - [ - ("system", system_template), - MessagesPlaceholder(variable_name="messages"), - ( - "human", - "User question: {input}" - ), - ] - ) - question_answering_chain = question_answering_prompt | llm + neo_db = initialize_neo4j_vector(graph, chat_mode_settings) + document_names= list(map(str.strip, json.loads(document_names))) + retriever = create_retriever(neo_db, document_names, search_k, score_threshold) + return retriever + except Exception as e: + logging.error(f"Error retrieving Neo4jVector index or creating retriever: {e}") + raise Exception("An error occurred while retrieving the Neo4jVector index or creating the retriever. Please drop and create a new vector index: {e}") from e - return question_answering_chain -def get_sources_and_chunks(sources_used, docs): - chunkdetails_list = [] - sources_used_set = set(sources_used) +def setup_chat(model, graph, document_names, chat_mode_settings): + start_time = time.time() + try: + if model == "diffbot": + model = "openai-gpt-4o" + + llm, model_name = get_llm(model=model) + logging.info(f"Model called in chat: {model} (version: {model_name})") - for doc in docs: - source = doc.metadata["source"] - chunkdetails = doc.metadata["chunkdetails"] - if source in sources_used_set: - chunkdetails = [{**chunkdetail, "score": round(chunkdetail["score"], 4)} for chunkdetail in chunkdetails] - chunkdetails_list.extend(chunkdetails) + retriever = get_neo4j_retriever(graph=graph, chat_mode_settings=chat_mode_settings, document_names=document_names) + doc_retriever = create_document_retriever_chain(llm, retriever) + + chat_setup_time = time.time() - start_time + logging.info(f"Chat setup completed in {chat_setup_time:.2f} seconds") + + except Exception as e: + logging.error(f"Error during chat setup: {e}", exc_info=True) + raise + + return llm, doc_retriever, model_name - result = { - 'sources': sources_used, - 'chunkdetails': chunkdetails_list - } - return result +def process_chat_response(messages,history, question, model, graph, document_names,chat_mode_settings): + try: + llm, doc_retriever, model_version = setup_chat(model, graph, document_names,chat_mode_settings) + + docs = retrieve_documents(doc_retriever, messages) + + if docs: + content, result, total_tokens = process_documents(docs, question, messages, llm, model) + else: + content = "I couldn't find any relevant documents to answer your question." + result = {"sources": [], "chunkdetails": []} + total_tokens = 0 + + ai_response = AIMessage(content=result["message"]) + messages.append(ai_response) + summarize_and_log(history, messages, llm) + + return { + "session_id": "", + "message": content, + "info": { + "sources": result["sources"], + "model": model_version, + "chunkdetails": result["chunkdetails"], + "total_tokens": total_tokens, + "response_time": 0, + "mode": chat_mode_settings["mode"] + }, + "user": "chatbot" + } + + except Exception as e: + logging.exception(f"Error processing chat response at {datetime.now()}: {str(e)}") + return { + "session_id": "", + "message": "Something went wrong", + "info": { + "sources": [], + "chunkdetails": [], + "total_tokens": 0, + "response_time": 0, + "error": f"{type(e).__name__}: {str(e)}", + "mode": chat_mode_settings["mode"] + }, + "user": "chatbot" + } -def summarize_messages(llm,history,stored_messages): - if len(stored_messages) == 0: +def summarize_and_log(history, stored_messages, llm): + if not stored_messages: + logging.info("No messages to summarize.") return False - summarization_prompt = ChatPromptTemplate.from_messages( - [ - MessagesPlaceholder(variable_name="chat_history"), - ( - "human", - "Summarize the above chat messages into a concise message, focusing on key points and relevant details that could be useful for future conversations. Exclude all introductions and extraneous information." - ), - ] - ) - - summarization_chain = summarization_prompt | llm - - summary_message = summarization_chain.invoke({"chat_history": stored_messages}) - - history.clear() - history.add_user_message("Our current convertaion summary till now") - history.add_message(summary_message) - return True - - -def get_total_tokens(ai_response,llm): - - if isinstance(llm,(ChatOpenAI,AzureChatOpenAI,ChatFireworks,ChatGroq)): - total_tokens = ai_response.response_metadata['token_usage']['total_tokens'] - elif isinstance(llm,(ChatVertexAI)): - total_tokens = ai_response.response_metadata['usage_metadata']['prompt_token_count'] - elif isinstance(llm,(ChatBedrock)): - total_tokens = ai_response.response_metadata['usage']['total_tokens'] - elif isinstance(llm,(ChatAnthropic)): - input_tokens = int(ai_response.response_metadata['usage']['input_tokens']) - output_tokens = int(ai_response.response_metadata['usage']['output_tokens']) - total_tokens = input_tokens + output_tokens - elif isinstance(llm,(ChatOllama)): - total_tokens = ai_response.response_metadata["prompt_eval_count"] - else: - total_tokens = 0 - return total_tokens + try: + start_time = time.time() -def clear_chat_history(graph,session_id): - history = Neo4jChatMessageHistory( - graph=graph, - session_id=session_id + summarization_prompt = ChatPromptTemplate.from_messages( + [ + MessagesPlaceholder(variable_name="chat_history"), + ( + "human", + "Summarize the above chat messages into a concise message, focusing on key points and relevant details that could be useful for future conversations. Exclude all introductions and extraneous information." + ), + ] ) - history.clear() - return { - "session_id": session_id, - "message": "The chat History is cleared", - "user": "chatbot" - } + summarization_chain = summarization_prompt | llm -def setup_chat(model, graph, document_names,retrieval_query,mode): - start_time = time.time() - if model in ["diffbot"]: - model = "openai-gpt-4o" - llm,model_name = get_llm(model) - logging.info(f"Model called in chat {model} and model version is {model_name}") - retriever = get_neo4j_retriever(graph=graph,retrieval_query=retrieval_query,document_names=document_names,mode=mode) - doc_retriever = create_document_retriever_chain(llm, retriever) - chat_setup_time = time.time() - start_time - logging.info(f"Chat setup completed in {chat_setup_time:.2f} seconds") - - return llm, doc_retriever, model_name + summary_message = summarization_chain.invoke({"chat_history": stored_messages}) -def retrieve_documents(doc_retriever, messages): - start_time = time.time() - docs = doc_retriever.invoke({"messages": messages}) - doc_retrieval_time = time.time() - start_time - logging.info(f"Documents retrieved in {doc_retrieval_time:.2f} seconds") - return docs + history.clear() + history.add_user_message("Our current conversation summary till now") + history.add_message(summary_message) -def process_documents(docs, question, messages, llm,model): - start_time = time.time() - formatted_docs, sources = format_documents(docs,model) - rag_chain = get_rag_chain(llm=llm) - ai_response = rag_chain.invoke({ - "messages": messages[:-1], - "context": formatted_docs, - "input": question - }) - result = get_sources_and_chunks(sources, docs) - content = ai_response.content - total_tokens = get_total_tokens(ai_response,llm) - - - predict_time = time.time() - start_time - logging.info(f"Final Response predicted in {predict_time:.2f} seconds") - - return content, result, total_tokens - -def summarize_and_log(history, messages, llm): - start_time = time.time() - summarize_messages(llm, history, messages) - history_summarized_time = time.time() - start_time - logging.info(f"Chat History summarized in {history_summarized_time:.2f} seconds") + history_summarized_time = time.time() - start_time + logging.info(f"Chat History summarized in {history_summarized_time:.2f} seconds") + return True + except Exception as e: + logging.error(f"An error occurred while summarizing messages: {e}") + return False + def create_graph_chain(model, graph): try: logging.info(f"Graph QA Chain using LLM model: {model}") @@ -346,79 +467,109 @@ def get_graph_response(graph_chain, question): except Exception as e: logging.error("An error occurred while getting the graph response : {e}") -def QA_RAG(graph, model, question, document_names,session_id, mode): +def process_graph_response(model, graph, question, messages, history): try: - logging.info(f"Chat Mode : {mode}") - history = create_neo4j_chat_message_history(graph, session_id) - messages = history.messages - user_question = HumanMessage(content=question) - messages.append(user_question) - - if mode == "graph": - graph_chain, qa_llm,model_version = create_graph_chain(model,graph) - graph_response = get_graph_response(graph_chain,question) - ai_response = AIMessage(content=graph_response["response"]) if graph_response["response"] else AIMessage(content="Something went wrong") - messages.append(ai_response) - summarize_and_log(history, messages, qa_llm) - - result = { - "session_id": session_id, - "message": graph_response["response"], - "info": { - "model": model_version, - 'cypher_query':graph_response["cypher_query"], - "context" : graph_response["context"], - "mode" : mode, - "response_time": 0 - }, - "user": "chatbot" - } - return result - elif mode == "vector" or mode == "fulltext": - retrieval_query = VECTOR_SEARCH_QUERY - else: - retrieval_query = VECTOR_GRAPH_SEARCH_QUERY.format(no_of_entites=VECTOR_GRAPH_SEARCH_ENTITY_LIMIT) - - llm, doc_retriever, model_version = setup_chat(model, graph, document_names,retrieval_query,mode) + graph_chain, qa_llm, model_version = create_graph_chain(model, graph) - docs = retrieve_documents(doc_retriever, messages) - - if docs: - content, result, total_tokens = process_documents(docs, question, messages, llm,model) - else: - content = "I couldn't find any relevant documents to answer your question." - result = {"sources": [], "chunkdetails": []} - total_tokens = 0 + graph_response = get_graph_response(graph_chain, question) + + ai_response_content = graph_response.get("response", "Something went wrong") + ai_response = AIMessage(content=ai_response_content) - ai_response = AIMessage(content=content) messages.append(ai_response) - summarize_and_log(history, messages, llm) + summarize_and_log(history, messages, qa_llm) - return { - "session_id": session_id, - "message": content, + result = { + "session_id": "", + "message": ai_response_content, "info": { - "sources": result["sources"], "model": model_version, - "chunkdetails": result["chunkdetails"], - "total_tokens": total_tokens, - "response_time": 0, - "mode": mode + "cypher_query": graph_response.get("cypher_query", ""), + "context": graph_response.get("context", ""), + "mode": "graph", + "response_time": 0 }, "user": "chatbot" } - + + return result + except Exception as e: - logging.exception(f"Exception in QA component at {datetime.now()}: {str(e)}") - error_name = type(e).__name__ + logging.exception(f"Error processing graph response at {datetime.now()}: {str(e)}") return { - "session_id": session_id, + "session_id": "", "message": "Something went wrong", "info": { - "sources": [], - "chunkids": [], - "error": f"{error_name} :- {str(e)}", - "mode": mode + "model": model_version, + "cypher_query": "", + "context": "", + "mode": "graph", + "response_time": 0, + "error": f"{type(e).__name__}: {str(e)}" }, "user": "chatbot" } + +def create_neo4j_chat_message_history(graph, session_id): + """ + Creates and returns a Neo4jChatMessageHistory instance. + + """ + try: + + history = Neo4jChatMessageHistory( + graph=graph, + session_id=session_id + ) + return history + + except Exception as e: + logging.error(f"Error creating Neo4jChatMessageHistory: {e}") + raise + +def get_chat_mode_settings(mode): + chat_mode_settings = {} + + # logging.info(f"Received mode: {mode}") + + try: + if mode in ["vector", "fulltext"]: + chat_mode_settings["retrieval_query"] = VECTOR_SEARCH_QUERY + chat_mode_settings["index_name"] = "vector" + chat_mode_settings["keyword_index"] = "keyword" + elif mode == "local_community_search": + chat_mode_settings["retrieval_query"] = LOCAL_COMMUNITY_SEARCH_QUERY + chat_mode_settings["index_name"] = "entity_vector" + chat_mode_settings["keyword_index"] = "" + elif mode in ['graph+vector', 'graph+vector+fulltext']: + chat_mode_settings["retrieval_query"] = VECTOR_GRAPH_SEARCH_QUERY.format(no_of_entites=VECTOR_GRAPH_SEARCH_ENTITY_LIMIT) + chat_mode_settings["index_name"] = "vector" + chat_mode_settings["keyword_index"] = "keyword" + else: + raise ValueError(f"Invalid mode: {mode}") + + logging.info(f"Chat mode settings: {chat_mode_settings}") + + except Exception as e: + logging.error(f"Unexpected error: {e}", exc_info=True) + raise e + + return chat_mode_settings + +def QA_RAG(graph, model, question, document_names, session_id, mode): + logging.info(f"Chat Mode: {mode}") + chat_mode_settings = get_chat_mode_settings(mode=mode) + + history = create_neo4j_chat_message_history(graph, session_id) + messages = history.messages + + user_question = HumanMessage(content=question) + messages.append(user_question) + + if mode == "graph": + result = process_graph_response(model, graph, question, messages, history) + else: + result = process_chat_response(messages,history, question, model, graph, document_names,chat_mode_settings) + + result["session_id"] = session_id + return result \ No newline at end of file diff --git a/backend/src/QA_optimization.py b/backend/src/QA_optimization.py deleted file mode 100644 index 70c5ffdc8..000000000 --- a/backend/src/QA_optimization.py +++ /dev/null @@ -1,217 +0,0 @@ -import os -from langchain_community.vectorstores.neo4j_vector import Neo4jVector -from langchain.chains import GraphCypherQAChain -from langchain.graphs import Neo4jGraph -from langchain.chains import RetrievalQA -from langchain_openai import ChatOpenAI -from langchain_openai import OpenAIEmbeddings -import logging -from langchain_community.chat_message_histories import Neo4jChatMessageHistory -import asyncio -from datetime import datetime -from dotenv import load_dotenv -load_dotenv() - -# openai_api_key = os.environ.get('OPENAI_API_KEY') -# model_version='gpt-4-0125-preview' - -class ParallelComponent: - - def __init__(self, uri, userName, password, question, session_id): - self.uri = uri - self.userName = userName - self.password = password - self.question = question - self.session_id = session_id - self.model_version='gpt-4-0125-preview' - self.llm = ChatOpenAI(model= self.model_version, temperature=0) - - # async def execute(self): - # tasks = [] - - # tasks.append(asyncio.create_task(self._vector_embed_results())) - # tasks.append(asyncio.create_task(self._cypher_results())) - # tasks.append(asyncio.create_task(self._get_chat_history())) - - # return await asyncio.gather(*tasks) - async def execute(self): - tasks = [ - self._vector_embed_results(), - # self._cypher_results(), ## Disabled call for cypher_results - self._get_chat_history() - ] - return await asyncio.gather(*tasks) - - async def _vector_embed_results(self): - t=datetime.now() - print("Vector embeddings start time",t) - # retrieval_query=""" - # MATCH (node)-[:__PART_OF__]->(d:Document) - # WITH d, apoc.text.join(collect(node.text),"\n----\n") as text, avg(score) as score - # RETURN text, score, {source: COALESCE(CASE WHEN d.url CONTAINS "None" THEN d.fileName ELSE d.url END, d.fileName)} as metadata - # """ - retrieval_query=""" - WITH node, score, apoc.text.join([ (node)-[:__HAS_ENTITY__]->(e) | head(labels(e)) + ": "+ e.id],", ") as entities - MATCH (node)-[:__PART_OF__]->(d:__Document__) - WITH d, apoc.text.join(collect(node.text + "\n" + entities),"\n----\n") as text, avg(score) as score - RETURN text, score, {source: COALESCE(CASE WHEN d.url CONTAINS "None" THEN d.fileName ELSE d.url END, d.fileName)} as metadata - """ - vector_res={} - try: - neo_db=Neo4jVector.from_existing_index( - embedding=OpenAIEmbeddings(), - url=self.uri, - username=self.userName, - password=self.password, - database="neo4j", - index_name="vector", - retrieval_query=retrieval_query, - ) - # llm = ChatOpenAI(model= model_version, temperature=0) - - qa = RetrievalQA.from_chain_type( - llm=self.llm, chain_type="stuff", retriever=neo_db.as_retriever(search_kwargs={'k': 3,"score_threshold": 0.5}), return_source_documents=True - ) - - result = qa({"query": self.question}) - vector_res['result']=result.get("result") - list_source_docs=[] - for i in result["source_documents"]: - list_source_docs.append(i.metadata['source']) - vector_res['source']=list_source_docs - except Exception as e: - error_message = str(e) - logging.exception(f'Exception in vector embedding in QA component:{error_message}') - # raise Exception(error_message) - print("Vector embeddings duration time",datetime.now()-t) - return vector_res - - - async def _cypher_results(self): - try: - t=datetime.now() - print("Cypher QA start time",t) - cypher_res={} - graph = Neo4jGraph( - url=self.uri, - username=self.userName, - password=self.password - ) - - - graph.refresh_schema() - cypher_chain = GraphCypherQAChain.from_llm( - graph=graph, - cypher_llm=ChatOpenAI(temperature=0, model=self.model_version), - qa_llm=ChatOpenAI(temperature=0, model=self.model_version), - validate_cypher=True, # Validate relationship directions - verbose=True, - top_k=2 - ) - try: - cypher_res=cypher_chain.invoke({"query": question}) - except: - cypher_res={} - - except Exception as e: - error_message = str(e) - logging.exception(f'Exception in CypherQAChain in QA component:{error_message}') - # raise Exception(error_message) - print("Cypher QA duration",datetime.now()-t) - return cypher_res - - async def _get_chat_history(self): - try: - t=datetime.now() - print("Get chat history start time:",t) - history = Neo4jChatMessageHistory( - url=self.uri, - username=self.userName, - password=self.password, - session_id=self.session_id - ) - chat_history=history.messages - - if len(chat_history)==0: - return {"result":""} - condense_template = f"""Given the following earlier conversation , Summarise the chat history.Make sure to include all the relevant information. - Chat History: - {chat_history}""" - chat_summary=self.llm.predict(condense_template) - print("Get chat history duration time:",datetime.now()-t) - return {"result":chat_summary} - except Exception as e: - error_message = str(e) - logging.exception(f'Exception in retrieving chat history:{error_message}') - # raise Exception(error_message) - return {"result":''} - - async def final_prompt(self,chat_summary,cypher_res,vector_res): - t=datetime.now() - print('Final prompt start time:',t) - final_prompt = f"""You are a helpful question-answering agent. Your task is to analyze - and synthesize information from two sources: the top result from a similarity search - (unstructured information) and relevant data from a graph database (structured information). - If structured information fails to find an answer then use the answer from unstructured information - and vice versa. I only want a straightforward answer without mentioning from which source you got the answer. You are also receiving - a chat history of the earlier conversation. You should be able to understand the context from the chat history and answer the question. - Given the user's query: {self.question}, provide a meaningful and efficient answer based - on the insights derived from the following data: - chat_summary:{chat_summary} - Structured information: {cypher_res}. - Unstructured information: {vector_res}. - - """ - print(final_prompt) - response = self.llm.predict(final_prompt) - ai_message=response - user_message=question - print('Final prompt duration',datetime.now()-t) - return ai_message,user_message - - - async def _save_chat_history(self,ai_message,user_message): - try: - history = Neo4jChatMessageHistory( - url=self.uri, - username=self.userName, - password=self.password, - session_id=self.session_id - ) - history.add_user_message(user_message) - history.add_ai_message(ai_message) - logging.info(f'Successfully saved chat history') - except Exception as e: - error_message = str(e) - logging.exception(f'Exception in saving chat history:{error_message}') - raise Exception(error_message) - -# Usage example: - -uri=os.environ.get('NEO4J_URI') -userName=os.environ.get('NEO4J_USERNAME') -password=os.environ.get('NEO4J_PASSWORD') -question='Do you know my name?' -session_id=2 - -async def main(uri,userName,password,question,session_id): - t=datetime.now() - parallel_component = ParallelComponent(uri, userName, password, question, session_id) - f_results=await parallel_component.execute() - print(f_results) - # f_vector_result=f_results[0]['result'] - # f_cypher_result=f_results[1].get('result','') - # f_chat_summary=f_results[2]['result'] - f_vector_result=f_results[0]['result'] - f_cypher_result = "" # Passing Empty string for cypher_result - f_chat_summary=f_results[1]['result'] - print(f_vector_result) - print(f_cypher_result) - print(f_chat_summary) - ai_message,user_message=await parallel_component.final_prompt(f_chat_summary,f_cypher_result,f_vector_result) - # print(asyncio.gather(asyncio.create_taskparallel_component.final_prompt(f_chat_summary,f_cypher_result,f_vector_result))) - await parallel_component._save_chat_history(ai_message,user_message) - print("Total Time taken:",datetime.now()-t) - print("Response from AI:",ai_message) -# Run with an event loop -asyncio.run(main(uri,userName,password,question,session_id)) \ No newline at end of file diff --git a/backend/src/shared/constants.py b/backend/src/shared/constants.py index c5f8e98a4..c4d56f963 100644 --- a/backend/src/shared/constants.py +++ b/backend/src/shared/constants.py @@ -276,4 +276,7 @@ RETURN text, avg_score as score, {{length:size(text), source: COALESCE( CASE WHEN d.url CONTAINS "None" THEN d.fileName ELSE d.url END, d.fileName), chunkdetails: chunkdetails}} AS metadata """ + +LOCAL_COMMUNITY_SEARCH_QUERY = """""" + YOUTUBE_CHUNK_SIZE_SECONDS = 60 From 6ba42e0a34934b7c0382de0e7338ba61ebcd6603 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Thu, 5 Sep 2024 11:59:03 +0000 Subject: [PATCH 049/292] allow credentials true changes --- backend/score.py | 1 - frontend/src/components/Content.tsx | 5 ++++- frontend/src/services/ServerSideStatusUpdateAPI.ts | 5 +---- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/backend/score.py b/backend/score.py index 15b381e83..7db8ab069 100644 --- a/backend/score.py +++ b/backend/score.py @@ -46,7 +46,6 @@ def sick(): app.add_middleware( CORSMiddleware, allow_origins=["*"], - allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 877c1178b..12213f66b 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -125,7 +125,10 @@ const Content: React.FC = ({ useEffect(() => { setFilesData((prevfiles) => { return prevfiles.map((curfile) => { - return { ...curfile, model: curfile.status === 'New' ? model : curfile.model }; + return { + ...curfile, + model: curfile.status === 'New' || curfile.status === 'Reprocess' ? model : curfile.model, + }; }); }); }, [model]); diff --git a/frontend/src/services/ServerSideStatusUpdateAPI.ts b/frontend/src/services/ServerSideStatusUpdateAPI.ts index dfef3a40f..547a929a8 100644 --- a/frontend/src/services/ServerSideStatusUpdateAPI.ts +++ b/frontend/src/services/ServerSideStatusUpdateAPI.ts @@ -8,10 +8,7 @@ export function triggerStatusUpdateAPI( database: string, datahandler: (i: eventResponsetypes) => void ) { - let encodedstr; - if (password) { - encodedstr = btoa(password); - } + let encodedstr: string = password ? btoa(password) : ''; const eventSource = new EventSource( `${url()}/update_extract_status/${name}?url=${uri}&userName=${username}&password=${encodedstr}&database=${database}` ); From 771753bf8bca4039c1dbcdd61096668da0aa1daa Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Thu, 5 Sep 2024 12:07:22 +0000 Subject: [PATCH 050/292] reset the values to 0 when the retry option is start from begining --- frontend/src/components/Content.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 12213f66b..939b973ec 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -513,15 +513,16 @@ const Content: React.FC = ({ if (response.data.status === 'Failure') { throw new Error(response.data.error); } + const isStartFromBegining = retryoption === RETRY_OPIONS[0]; setFilesData((prev) => { return prev.map((f) => { return f.name === filename ? { ...f, status: 'Reprocess', - processingProgress: retryoption.includes('start_from_beginning') ? 0 : f.processingProgress, - NodesCount: retryoption === RETRY_OPIONS[1] ? 0 : f.NodesCount, - relationshipCount: retryoption === RETRY_OPIONS[1] ? 0 : f.relationshipCount, + processingProgress: isStartFromBegining ? 0 : f.processingProgress, + NodesCount: isStartFromBegining ? 0 : f.NodesCount, + relationshipCount: isStartFromBegining ? 0 : f.relationshipCount, } : f; }); From d56a60d426ef9bbc78ff0b4c34d07c26aa5cd608 Mon Sep 17 00:00:00 2001 From: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Date: Thu, 5 Sep 2024 12:11:45 +0000 Subject: [PATCH 051/292] Update Node/Document status using SSE, Trying to fix Cancelled by Scope error --- backend/score.py | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/backend/score.py b/backend/score.py index 7db8ab069..52bd166bb 100644 --- a/backend/score.py +++ b/backend/score.py @@ -433,25 +433,25 @@ async def generate(): logging.info(" SSE Client disconnected") break # get the current status of document node - graph = create_graph_database_connection(uri, userName, decoded_password, database) - graphDb_data_Access = graphDBdataAccess(graph) - result = graphDb_data_Access.get_current_status_document_node(file_name) - print(f'Result of document status in SSE : {result}') - if len(result) > 0: - status = json.dumps({'fileName':file_name, - 'status':result[0]['Status'], - 'processingTime':result[0]['processingTime'], - 'nodeCount':result[0]['nodeCount'], - 'relationshipCount':result[0]['relationshipCount'], - 'model':result[0]['model'], - 'total_chunks':result[0]['total_chunks'], - 'fileSize':result[0]['fileSize'], - 'processed_chunk':result[0]['processed_chunk'], - 'fileSource':result[0]['fileSource'] - }) + else: - status = json.dumps({'fileName':file_name, 'status':'Failed'}) - yield status + graph = create_graph_database_connection(uri, userName, decoded_password, database) + graphDb_data_Access = graphDBdataAccess(graph) + result = graphDb_data_Access.get_current_status_document_node(file_name) + print(f'Result of document status in SSE : {result}') + if len(result) > 0: + status = json.dumps({'fileName':file_name, + 'status':result[0]['Status'], + 'processingTime':result[0]['processingTime'], + 'nodeCount':result[0]['nodeCount'], + 'relationshipCount':result[0]['relationshipCount'], + 'model':result[0]['model'], + 'total_chunks':result[0]['total_chunks'], + 'fileSize':result[0]['fileSize'], + 'processed_chunk':result[0]['processed_chunk'], + 'fileSource':result[0]['fileSource'] + }) + yield status except asyncio.CancelledError: logging.info("SSE Connection cancelled") From 3f98459e3100550be57c86282fe0d6003c4e0771 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Thu, 5 Sep 2024 14:13:55 +0000 Subject: [PATCH 052/292] modified the chat mode settings --- backend/src/QA_integration_new.py | 126 +++++++++++++++++++----------- 1 file changed, 79 insertions(+), 47 deletions(-) diff --git a/backend/src/QA_integration_new.py b/backend/src/QA_integration_new.py index 6fe4907f1..e595a820e 100644 --- a/backend/src/QA_integration_new.py +++ b/backend/src/QA_integration_new.py @@ -1,29 +1,26 @@ -from langchain_community.vectorstores.neo4j_vector import Neo4jVector import os +import json +from datetime import datetime +import time +from typing import Any + from dotenv import load_dotenv import logging + +# LangChain imports +from langchain_community.vectorstores.neo4j_vector import Neo4jVector from langchain_community.chat_message_histories import Neo4jChatMessageHistory -from src.llm import get_llm -from src.shared.common_fn import load_embedding_model -import re -from typing import Any -from datetime import datetime -import time from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain_core.output_parsers import StrOutputParser from langchain_core.runnables import RunnableBranch from langchain.retrievers import ContextualCompressionRetriever from langchain_community.document_transformers import EmbeddingsRedundantFilter -from langchain.retrievers.document_compressors import EmbeddingsFilter -from langchain.retrievers.document_compressors import DocumentCompressorPipeline +from langchain.retrievers.document_compressors import EmbeddingsFilter, DocumentCompressorPipeline from langchain_text_splitters import TokenTextSplitter -from langchain_core.messages import HumanMessage,AIMessage -from src.shared.constants import * -from src.llm import get_llm +from langchain_core.messages import HumanMessage, AIMessage from langchain.chains import GraphCypherQAChain -import json -## Chat models +# LangChain chat models from langchain_openai import ChatOpenAI, AzureChatOpenAI from langchain_google_vertexai import ChatVertexAI from langchain_groq import ChatGroq @@ -32,6 +29,11 @@ from langchain_aws import ChatBedrock from langchain_community.chat_models import ChatOllama +# Local imports +from src.llm import get_llm +from src.shared.common_fn import load_embedding_model +from src.shared.constants import * + load_dotenv() EMBEDDING_MODEL = os.getenv('EMBEDDING_MODEL') @@ -91,23 +93,27 @@ def clear_chat_history(graph, session_id): def get_sources_and_chunks(sources_used, docs): chunkdetails_list = [] - sources_used_set = set(sources_used) + seen_ids_and_scores = set() for doc in docs: try: source = doc.metadata.get("source") chunkdetails = doc.metadata.get("chunkdetails", []) - + if source in sources_used_set: - formatted_chunkdetails = [ - {**chunkdetail, "score": round(chunkdetail.get("score", 0), 4)} - for chunkdetail in chunkdetails - ] - chunkdetails_list.extend(formatted_chunkdetails) - + for chunkdetail in chunkdetails: + id = chunkdetail.get("id") + score = round(chunkdetail.get("score", 0), 4) + + id_and_score = (id, score) + + if id_and_score not in seen_ids_and_scores: + seen_ids_and_scores.add(id_and_score) + chunkdetails_list.append({**chunkdetail, "score": score}) + except Exception as e: - logging.error(f"Error processing document: {e}", exc_info=True) + logging.error(f"Error processing document: {e}") result = { 'sources': sources_used, @@ -261,7 +267,7 @@ def initialize_neo4j_vector(graph, chat_mode_settings): if not retrieval_query or not index_name: raise ValueError("Required settings 'retrieval_query' or 'index_name' are missing.") - if mode in ["fulltext", "graph+vector+fulltext"]: + if keyword_index: neo_db = Neo4jVector.from_existing_graph( embedding=EMBEDDING_FUNCTION, index_name=index_name, @@ -281,15 +287,15 @@ def initialize_neo4j_vector(graph, chat_mode_settings): retrieval_query=retrieval_query, graph=graph ) + logging.info(f"Successfully retrieved Neo4jVector index '{index_name}'") - except Exception as e: logging.error(f"Error retrieving Neo4jVector index : {e}") raise return neo_db -def create_retriever(neo_db, document_names, search_k, score_threshold): - if document_names: +def create_retriever(neo_db, document_names, chat_mode_settings,search_k, score_threshold): + if document_names and chat_mode_settings["document_filter"]: retriever = neo_db.as_retriever( search_type="similarity_score_threshold", search_kwargs={ @@ -312,7 +318,7 @@ def get_neo4j_retriever(graph, document_names,chat_mode_settings, search_k=CHAT_ neo_db = initialize_neo4j_vector(graph, chat_mode_settings) document_names= list(map(str.strip, json.loads(document_names))) - retriever = create_retriever(neo_db, document_names, search_k, score_threshold) + retriever = create_retriever(neo_db, document_names,chat_mode_settings, search_k, score_threshold) return retriever except Exception as e: logging.error(f"Error retrieving Neo4jVector index or creating retriever: {e}") @@ -353,7 +359,7 @@ def process_chat_response(messages,history, question, model, graph, document_nam result = {"sources": [], "chunkdetails": []} total_tokens = 0 - ai_response = AIMessage(content=result["message"]) + ai_response = AIMessage(content=content) messages.append(ai_response) summarize_and_log(history, messages, llm) @@ -528,37 +534,61 @@ def create_neo4j_chat_message_history(graph, session_id): raise def get_chat_mode_settings(mode): - chat_mode_settings = {} - # logging.info(f"Received mode: {mode}") + settings_map = { + "vector": { + "retrieval_query": VECTOR_SEARCH_QUERY, + "index_name": "vector", + "keyword_index": None, + "document_filter": True + }, + "fulltext": { + "retrieval_query": VECTOR_SEARCH_QUERY, + "index_name": "vector", + "keyword_index": "keyword", + "document_filter": False + }, + "local_community_search": { + "retrieval_query": LOCAL_COMMUNITY_SEARCH_QUERY, + "index_name": "entity_vector", + "keyword_index": None, + "document_filter": False + }, + "graph+vector": { + "retrieval_query": VECTOR_GRAPH_SEARCH_QUERY.format(no_of_entites=VECTOR_GRAPH_SEARCH_ENTITY_LIMIT), + "index_name": "vector", + "keyword_index": None, + "document_filter": True + }, + "graph+vector+fulltext": { + "retrieval_query": VECTOR_GRAPH_SEARCH_QUERY.format(no_of_entites=VECTOR_GRAPH_SEARCH_ENTITY_LIMIT), + "index_name": "vector", + "keyword_index": "keyword", + "document_filter": False + } + } + + default_settings = { + "retrieval_query": VECTOR_SEARCH_QUERY, + "index_name": "vector", + "keyword_index": None, + "document_filter": False + } try: - if mode in ["vector", "fulltext"]: - chat_mode_settings["retrieval_query"] = VECTOR_SEARCH_QUERY - chat_mode_settings["index_name"] = "vector" - chat_mode_settings["keyword_index"] = "keyword" - elif mode == "local_community_search": - chat_mode_settings["retrieval_query"] = LOCAL_COMMUNITY_SEARCH_QUERY - chat_mode_settings["index_name"] = "entity_vector" - chat_mode_settings["keyword_index"] = "" - elif mode in ['graph+vector', 'graph+vector+fulltext']: - chat_mode_settings["retrieval_query"] = VECTOR_GRAPH_SEARCH_QUERY.format(no_of_entites=VECTOR_GRAPH_SEARCH_ENTITY_LIMIT) - chat_mode_settings["index_name"] = "vector" - chat_mode_settings["keyword_index"] = "keyword" - else: - raise ValueError(f"Invalid mode: {mode}") + chat_mode_settings = settings_map.get(mode, default_settings) + chat_mode_settings["mode"] = mode logging.info(f"Chat mode settings: {chat_mode_settings}") except Exception as e: logging.error(f"Unexpected error: {e}", exc_info=True) - raise e + raise return chat_mode_settings def QA_RAG(graph, model, question, document_names, session_id, mode): logging.info(f"Chat Mode: {mode}") - chat_mode_settings = get_chat_mode_settings(mode=mode) history = create_neo4j_chat_message_history(graph, session_id) messages = history.messages @@ -569,7 +599,9 @@ def QA_RAG(graph, model, question, document_names, session_id, mode): if mode == "graph": result = process_graph_response(model, graph, question, messages, history) else: + chat_mode_settings = get_chat_mode_settings(mode=mode) result = process_chat_response(messages,history, question, model, graph, document_names,chat_mode_settings) result["session_id"] = session_id + return result \ No newline at end of file From 09b0180af013d32921a87decd20add7fad987605 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Thu, 5 Sep 2024 14:27:14 +0000 Subject: [PATCH 053/292] renamed QA_integration --- backend/score.py | 2 +- backend/src/{QA_integration_new.py => QA_integration.py} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename backend/src/{QA_integration_new.py => QA_integration.py} (100%) diff --git a/backend/score.py b/backend/score.py index 19f7ddb1a..329c8f5b2 100644 --- a/backend/score.py +++ b/backend/score.py @@ -2,7 +2,7 @@ from fastapi_health import health from fastapi.middleware.cors import CORSMiddleware from src.main import * -from src.QA_integration_new import * +from src.QA_integration import * from src.entities.user_credential import user_credential from src.shared.common_fn import * import uvicorn diff --git a/backend/src/QA_integration_new.py b/backend/src/QA_integration.py similarity index 100% rename from backend/src/QA_integration_new.py rename to backend/src/QA_integration.py From 19b7bf2f67af47484062872e71c9373bc3984647 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Thu, 5 Sep 2024 14:43:09 +0000 Subject: [PATCH 054/292] added graphdatascience --- backend/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/requirements.txt b/backend/requirements.txt index 46c57aea5..b83a76b82 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -179,3 +179,4 @@ sentence-transformers==3.0.1 google-cloud-logging==3.10.0 PyMuPDF==1.24.5 pypandoc==1.13 +graphdatascience==1.10 From c91febba99224ef963065f059f46835165d120ce Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Thu, 5 Sep 2024 14:49:41 +0000 Subject: [PATCH 055/292] moved settings to constants --- backend/src/QA_integration.py | 44 ++------------------------------- backend/src/shared/constants.py | 38 ++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 42 deletions(-) diff --git a/backend/src/QA_integration.py b/backend/src/QA_integration.py index e595a820e..72c1232fa 100644 --- a/backend/src/QA_integration.py +++ b/backend/src/QA_integration.py @@ -533,48 +533,8 @@ def create_neo4j_chat_message_history(graph, session_id): logging.error(f"Error creating Neo4jChatMessageHistory: {e}") raise -def get_chat_mode_settings(mode): - - settings_map = { - "vector": { - "retrieval_query": VECTOR_SEARCH_QUERY, - "index_name": "vector", - "keyword_index": None, - "document_filter": True - }, - "fulltext": { - "retrieval_query": VECTOR_SEARCH_QUERY, - "index_name": "vector", - "keyword_index": "keyword", - "document_filter": False - }, - "local_community_search": { - "retrieval_query": LOCAL_COMMUNITY_SEARCH_QUERY, - "index_name": "entity_vector", - "keyword_index": None, - "document_filter": False - }, - "graph+vector": { - "retrieval_query": VECTOR_GRAPH_SEARCH_QUERY.format(no_of_entites=VECTOR_GRAPH_SEARCH_ENTITY_LIMIT), - "index_name": "vector", - "keyword_index": None, - "document_filter": True - }, - "graph+vector+fulltext": { - "retrieval_query": VECTOR_GRAPH_SEARCH_QUERY.format(no_of_entites=VECTOR_GRAPH_SEARCH_ENTITY_LIMIT), - "index_name": "vector", - "keyword_index": "keyword", - "document_filter": False - } - } - - default_settings = { - "retrieval_query": VECTOR_SEARCH_QUERY, - "index_name": "vector", - "keyword_index": None, - "document_filter": False - } - +def get_chat_mode_settings(mode,settings_map=CHAT_MODE_CONFIG_MAP): + default_settings = settings_map["default"] try: chat_mode_settings = settings_map.get(mode, default_settings) chat_mode_settings["mode"] = mode diff --git a/backend/src/shared/constants.py b/backend/src/shared/constants.py index c4d56f963..303e8d656 100644 --- a/backend/src/shared/constants.py +++ b/backend/src/shared/constants.py @@ -279,4 +279,42 @@ LOCAL_COMMUNITY_SEARCH_QUERY = """""" +CHAT_MODE_CONFIG_MAP= { + "vector": { + "retrieval_query": VECTOR_SEARCH_QUERY, + "index_name": "vector", + "keyword_index": None, + "document_filter": True + }, + "fulltext": { + "retrieval_query": VECTOR_SEARCH_QUERY, + "index_name": "vector", + "keyword_index": "keyword", + "document_filter": False + }, + "local_community_search": { + "retrieval_query": LOCAL_COMMUNITY_SEARCH_QUERY, + "index_name": "entity_vector", + "keyword_index": None, + "document_filter": False + }, + "graph+vector": { + "retrieval_query": VECTOR_GRAPH_SEARCH_QUERY.format(no_of_entites=VECTOR_GRAPH_SEARCH_ENTITY_LIMIT), + "index_name": "vector", + "keyword_index": None, + "document_filter": True + }, + "graph+vector+fulltext": { + "retrieval_query": VECTOR_GRAPH_SEARCH_QUERY.format(no_of_entites=VECTOR_GRAPH_SEARCH_ENTITY_LIMIT), + "index_name": "vector", + "keyword_index": "keyword", + "document_filter": False + }, + "default": { + "retrieval_query": VECTOR_SEARCH_QUERY, + "index_name": "vector", + "keyword_index": None, + "document_filter": True + } + } YOUTUBE_CHUNK_SIZE_SECONDS = 60 From 169c2727820ea0469c88bf6ccfa10a46617442fe Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Thu, 5 Sep 2024 16:36:10 +0000 Subject: [PATCH 056/292] modified constants --- backend/src/shared/constants.py | 141 +++++++++++++------------------- 1 file changed, 56 insertions(+), 85 deletions(-) diff --git a/backend/src/shared/constants.py b/backend/src/shared/constants.py index 303e8d656..c15602e25 100644 --- a/backend/src/shared/constants.py +++ b/backend/src/shared/constants.py @@ -68,7 +68,6 @@ ("ollama_llama3") : 2 } - ### CHAT TEMPLATES CHAT_SYSTEM_TEMPLATE = """ You are an AI-powered question-answering agent. Your task is to provide accurate and comprehensive responses to user queries based on the given context, chat history, and available resources. @@ -115,7 +114,6 @@ QUESTION_TRANSFORM_TEMPLATE = "Given the below conversation, generate a search query to look up in order to get information relevant to the conversation. Only respond with the query, nothing else." - ## CHAT QUERIES VECTOR_SEARCH_QUERY = """ WITH node AS chunk, score @@ -130,88 +128,6 @@ {source: COALESCE(CASE WHEN d.url CONTAINS "None" THEN d.fileName ELSE d.url END, d.fileName), chunkdetails: chunkdetails} as metadata """ -# VECTOR_GRAPH_SEARCH_QUERY=""" -# WITH node as chunk, score -# MATCH (chunk)-[:__PART_OF__]->(d:__Document__) -# CALL { WITH chunk -# MATCH (chunk)-[:__HAS_ENTITY__]->(e) -# MATCH path=(e)(()-[rels:!__HAS_ENTITY__&!__PART_OF__]-()){0,2}(:!__Chunk__&!__Document__) -# UNWIND rels as r -# RETURN collect(distinct r) as rels -# } -# WITH d, collect(DISTINCT {chunk: chunk, score: score}) AS chunks, avg(score) as avg_score, apoc.coll.toSet(apoc.coll.flatten(collect(rels))) as rels -# WITH d, avg_score, -# [c IN chunks | c.chunk.text] AS texts, -# [c IN chunks | {id: c.chunk.id, score: c.score}] AS chunkdetails, -# [r in rels | coalesce(apoc.coll.removeAll(labels(startNode(r)),['__Entity__'])[0],"") +":"+ startNode(r).id + " "+ type(r) + " " + coalesce(apoc.coll.removeAll(labels(endNode(r)),['__Entity__'])[0],"") +":" + endNode(r).id] as entities -# WITH d, avg_score,chunkdetails, -# apoc.text.join(texts,"\n----\n") + -# apoc.text.join(entities,"\n") -# as text -# RETURN text, avg_score AS score, {source: COALESCE( CASE WHEN d.url CONTAINS "None" THEN d.fileName ELSE d.url END, d.fileName), chunkdetails: chunkdetails} AS metadata -# """ - - -# VECTOR_GRAPH_SEARCH_QUERY = """ -# WITH node as chunk, score -# // find the document of the chunk -# MATCH (chunk)-[:__PART_OF__]->(d:__Document__) -# // fetch entities -# CALL { WITH chunk -# // entities connected to the chunk -# // todo only return entities that are actually in the chunk, remember we connect all extracted entities to all chunks -# MATCH (chunk)-[:__HAS_ENTITY__]->(e) - -# // depending on match to query embedding either 1 or 2 step expansion -# WITH CASE WHEN true // vector.similarity.cosine($embedding, e.embedding ) <= 0.95 -# THEN -# collect { MATCH path=(e)(()-[rels:!__HAS_ENTITY__&!__PART_OF__]-()){0,1}(:!Chunk&!__Document__) RETURN path } -# ELSE -# collect { MATCH path=(e)(()-[rels:!__HAS_ENTITY__&!__PART_OF__]-()){0,2}(:!Chunk&!__Document__) RETURN path } -# END as paths - -# RETURN collect{ unwind paths as p unwind relationships(p) as r return distinct r} as rels, -# collect{ unwind paths as p unwind nodes(p) as n return distinct n} as nodes -# } -# // aggregate chunk-details and de-duplicate nodes and relationships -# WITH d, collect(DISTINCT {chunk: chunk, score: score}) AS chunks, avg(score) as avg_score, apoc.coll.toSet(apoc.coll.flatten(collect(rels))) as rels, - -# // TODO sort by relevancy (embeddding comparision?) cut off after X (e.g. 25) nodes? -# apoc.coll.toSet(apoc.coll.flatten(collect( -# [r in rels |[startNode(r),endNode(r)]]),true)) as nodes - -# // generate metadata and text components for chunks, nodes and relationships -# WITH d, avg_score, -# [c IN chunks | c.chunk.text] AS texts, -# [c IN chunks | {id: c.chunk.id, score: c.score}] AS chunkdetails, -# apoc.coll.sort([n in nodes | - -# coalesce(apoc.coll.removeAll(labels(n),['__Entity__'])[0],"") +":"+ -# n.id + (case when n.description is not null then " ("+ n.description+")" else "" end)]) as nodeTexts, -# apoc.coll.sort([r in rels -# // optional filter if we limit the node-set -# // WHERE startNode(r) in nodes AND endNode(r) in nodes -# | -# coalesce(apoc.coll.removeAll(labels(startNode(r)),['__Entity__'])[0],"") +":"+ -# startNode(r).id + -# " " + type(r) + " " + -# coalesce(apoc.coll.removeAll(labels(endNode(r)),['__Entity__'])[0],"") +":" + -# endNode(r).id -# ]) as relTexts - -# // combine texts into response-text -# WITH d, avg_score,chunkdetails, -# "Text Content:\n" + -# apoc.text.join(texts,"\n----\n") + -# "\n----\nEntities:\n"+ -# apoc.text.join(nodeTexts,"\n") + -# "\n----\nRelationships:\n"+ -# apoc.text.join(relTexts,"\n") - -# as text -# RETURN text, avg_score as score, {length:size(text), source: COALESCE( CASE WHEN d.url CONTAINS "None" THEN d.fileName ELSE d.url END, d.fileName), chunkdetails: chunkdetails} AS metadata -# """ - VECTOR_GRAPH_SEARCH_ENTITY_LIMIT = 25 VECTOR_GRAPH_SEARCH_QUERY = """ @@ -277,7 +193,62 @@ RETURN text, avg_score as score, {{length:size(text), source: COALESCE( CASE WHEN d.url CONTAINS "None" THEN d.fileName ELSE d.url END, d.fileName), chunkdetails: chunkdetails}} AS metadata """ -LOCAL_COMMUNITY_SEARCH_QUERY = """""" + +### Local community search +LOCAL_COMMUNITY_TOP_CHUNKS = 3 +LOCAL_COMMUNITY_TOP_COMMUNITIES = 3 +LOCAL_COMMUNITY_TOP_OUTSIDE_RELS = 10 +LOCAL_COMMUNITY_TOP_INSIDE_RELS = 10 +LOCAL_COMMUNITY_TOP_ENTITIES = 10 + +LOCAL_COMMUNITY_SEARCH_QUERY = """ +WITH collect(node) as nodes +WITH +collect { + UNWIND nodes as n + MATCH (n)<-[:HAS_ENTITY]->(c:Chunk) + WITH c, count(distinct n) as freq + RETURN c.text AS chunkText + ORDER BY freq DESC + LIMIT $topChunks +} AS text_mapping, +// Entity - Report Mapping +collect { + UNWIND nodes as n + MATCH (n)-[:IN_COMMUNITY]->(c:__Community__) + WITH c, c.rank as rank, c.weight AS weight + RETURN c.summary + ORDER BY rank, weight DESC + LIMIT $topCommunities +} AS report_mapping, +// Outside Relationships +collect { + UNWIND nodes as n + MATCH (n)-[r:RELATED]-(m) + WHERE NOT m IN nodes + RETURN r.description AS descriptionText + ORDER BY r.rank, r.weight DESC + LIMIT $topOutsideRels +} as outsideRels, +// Inside Relationships +collect { + UNWIND nodes as n + MATCH (n)-[r:RELATED]-(m) + WHERE m IN nodes + RETURN r.description AS descriptionText + ORDER BY r.rank, r.weight DESC + LIMIT $topInsideRels +} as insideRels, +// Entities description +collect { + UNWIND nodes as n + RETURN n.description AS descriptionText +} as entities +// We don't have covariates or claims here +RETURN {Chunks: text_mapping, Reports: report_mapping, + Relationships: outsideRels + insideRels, + Entities: entities} AS text, 1.0 AS score, {} AS metadata +""" CHAT_MODE_CONFIG_MAP= { "vector": { From ba131448d313e97e7d6fe8816a230ad4096ebb33 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Fri, 6 Sep 2024 06:36:36 +0000 Subject: [PATCH 057/292] resetting the nodescount and relationshipcount --- frontend/src/components/Content.tsx | 2 +- frontend/src/components/FileTable.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 939b973ec..c77660212 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -513,7 +513,7 @@ const Content: React.FC = ({ if (response.data.status === 'Failure') { throw new Error(response.data.error); } - const isStartFromBegining = retryoption === RETRY_OPIONS[0]; + const isStartFromBegining = retryoption === RETRY_OPIONS[0] || retryoption===RETRY_OPIONS[1]; setFilesData((prev) => { return prev.map((f) => { return f.name === filename diff --git a/frontend/src/components/FileTable.tsx b/frontend/src/components/FileTable.tsx index aa4d9bb9a..04e2a8841 100644 --- a/frontend/src/components/FileTable.tsx +++ b/frontend/src/components/FileTable.tsx @@ -146,7 +146,7 @@ const FileTable = forwardRef((props, ref) => { > {info.getValue()} - {(info.getValue() === 'Completed' || + {/* {(info.getValue() === 'Completed' || info.getValue() === 'Failed' || info.getValue() === 'Cancelled') && ( @@ -161,7 +161,7 @@ const FileTable = forwardRef((props, ref) => { - )} + )} */}
); } else if (info.getValue() === 'Processing' && info.row.original.processingProgress === undefined) { From 4cc8104a0996c5d81ec8eb054d9439b0f8bb0528 Mon Sep 17 00:00:00 2001 From: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Date: Fri, 6 Sep 2024 07:46:48 +0000 Subject: [PATCH 058/292] Add vector index exist condition to create --- backend/src/make_relationships.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/backend/src/make_relationships.py b/backend/src/make_relationships.py index 3045649d5..4783c5abe 100644 --- a/backend/src/make_relationships.py +++ b/backend/src/make_relationships.py @@ -67,20 +67,23 @@ def update_embedding_create_vector_index(graph, chunkId_chunkDoc_list, file_name # ) # logging.info('create vector index on chunk embedding') result = graph.query("SHOW INDEXES YIELD * WHERE labelsOrTypes = ['__Chunk__'] and name = 'vector'") + vector_index = graph.query("SHOW INDEXES YIELD * WHERE labelsOrTypes = ['Chunk'] and type = 'VECTOR' AND name = 'vector' return options") if result: logging.info(f"vector index dropped for 'Chunk'") graph.query("DROP INDEX vector IF EXISTS;") - graph.query("""CREATE VECTOR INDEX `vector` if not exists for (c:Chunk) on (c.embedding) - OPTIONS {indexConfig: { - `vector.dimensions`: $dimensions, - `vector.similarity_function`: 'cosine' - }} - """, - { - "dimensions" : dimension - } - ) + if len(vector_index) == 0: + logging.info(f'vector index is not exist, will create in next query') + graph.query("""CREATE VECTOR INDEX `vector` if not exists for (c:Chunk) on (c.embedding) + OPTIONS {indexConfig: { + `vector.dimensions`: $dimensions, + `vector.similarity_function`: 'cosine' + }} + """, + { + "dimensions" : dimension + } + ) query_to_create_embedding = """ UNWIND $data AS row From 1222942539022e0c3ea0ee79dca9845fc6c95d67 Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Fri, 6 Sep 2024 20:27:25 +0530 Subject: [PATCH 059/292] Science Molecule & database icon addition (#722) * DataScience icon addition * added gds status to connect call * icon stroke changes --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> --- backend/src/graphDB_dataAccess.py | 32 ++++++++++++++++--- frontend/src/components/ChatBot/Chatbot.tsx | 2 +- .../ChatBot/ExpandedChatButtonContainer.tsx | 2 +- frontend/src/components/Content.tsx | 16 ++++++---- .../components/DataSources/Local/DropZone.tsx | 2 +- frontend/src/components/FileTable.tsx | 2 +- .../src/components/Graph/GraphViewModal.tsx | 2 +- frontend/src/components/Layout/Header.tsx | 2 +- frontend/src/components/Layout/SideNav.tsx | 2 +- frontend/src/components/UI/DatabaseIcon.tsx | 25 +++++++++++++++ .../src/components/UI/IconButtonToolTip.tsx | 27 ++++++++++++++-- .../WebSources/GenericSourceButton.tsx | 2 +- frontend/src/types.ts | 6 ++++ frontend/src/utils/Constants.ts | 8 +++++ 14 files changed, 108 insertions(+), 22 deletions(-) create mode 100644 frontend/src/components/UI/DatabaseIcon.tsx diff --git a/backend/src/graphDB_dataAccess.py b/backend/src/graphDB_dataAccess.py index c77a1e773..7866c81c4 100644 --- a/backend/src/graphDB_dataAccess.py +++ b/backend/src/graphDB_dataAccess.py @@ -140,6 +140,27 @@ def update_KNN_graph(self): ) else: logging.info("Vector index does not exist, So KNN graph not update") + + def check_gds_version(self): + try: + gds_procedure_count = """ + SHOW PROCEDURES + YIELD name + WHERE name STARTS WITH "gds." + RETURN COUNT(*) AS totalGdsProcedures + """ + result = self.graph.query(gds_procedure_count) + total_gds_procedures = result[0]['totalGdsProcedures'] if result else 0 + + if total_gds_procedures > 0: + logging.info("GDS is available in the database.") + return True + else: + logging.info("GDS is not available in the database.") + return False + except Exception as e: + logging.error(f"An error occurred while checking GDS version: {e}") + return False def connection_check_and_get_vector_dimensions(self): """ @@ -166,19 +187,20 @@ def connection_check_and_get_vector_dimensions(self): embedding_model = os.getenv('EMBEDDING_MODEL') embeddings, application_dimension = load_embedding_model(embedding_model) logging.info(f'embedding model:{embeddings} and dimesion:{application_dimension}') - # print(chunks_exists) + + gds_status = self.check_gds_version() if self.graph: if len(db_vector_dimension) > 0: - return {'db_vector_dimension': db_vector_dimension[0]['vector_dimensions'], 'application_dimension':application_dimension, 'message':"Connection Successful"} + return {'db_vector_dimension': db_vector_dimension[0]['vector_dimensions'], 'application_dimension':application_dimension, 'message':"Connection Successful","gds_status":gds_status} else: if len(db_vector_dimension) == 0 and len(result_chunks) == 0: logging.info("Chunks and vector index does not exists in database") - return {'db_vector_dimension': 0, 'application_dimension':application_dimension, 'message':"Connection Successful","chunks_exists":False} + return {'db_vector_dimension': 0, 'application_dimension':application_dimension, 'message':"Connection Successful","chunks_exists":False,"gds_status":gds_status} elif len(db_vector_dimension) == 0 and result_chunks[0]['hasEmbedding']==0 and result_chunks[0]['chunks'] > 0: - return {'db_vector_dimension': 0, 'application_dimension':application_dimension, 'message':"Connection Successful","chunks_exists":True} + return {'db_vector_dimension': 0, 'application_dimension':application_dimension, 'message':"Connection Successful","chunks_exists":True,"gds_status":gds_status} else: - return {'message':"Connection Successful"} + return {'message':"Connection Successful","gds_status":gds_status} def execute_query(self, query, param=None): return self.graph.query(query, param) diff --git a/frontend/src/components/ChatBot/Chatbot.tsx b/frontend/src/components/ChatBot/Chatbot.tsx index da5aaaf29..05541aeff 100644 --- a/frontend/src/components/ChatBot/Chatbot.tsx +++ b/frontend/src/components/ChatBot/Chatbot.tsx @@ -14,7 +14,7 @@ import { v4 as uuidv4 } from 'uuid'; import { useFileContext } from '../../context/UsersFiles'; import clsx from 'clsx'; import ReactMarkdown from 'react-markdown'; -import IconButtonWithToolTip from '../UI/IconButtonToolTip'; +import { IconButtonWithToolTip } from '../UI/IconButtonToolTip'; import { buttonCaptions, tooltips } from '../../utils/Constants'; import useSpeechSynthesis from '../../hooks/useSpeech'; import ButtonWithToolTip from '../UI/ButtonWithToolTip'; diff --git a/frontend/src/components/ChatBot/ExpandedChatButtonContainer.tsx b/frontend/src/components/ChatBot/ExpandedChatButtonContainer.tsx index 49925466f..465687c4b 100644 --- a/frontend/src/components/ChatBot/ExpandedChatButtonContainer.tsx +++ b/frontend/src/components/ChatBot/ExpandedChatButtonContainer.tsx @@ -2,7 +2,7 @@ import { TrashIconOutline, XMarkIconOutline } from '@neo4j-ndl/react/icons'; import ChatModeToggle from './ChatModeToggle'; import { Box, IconButton } from '@neo4j-ndl/react'; import { IconProps } from '../../types'; -import IconButtonWithToolTip from '../UI/IconButtonToolTip'; +import { IconButtonWithToolTip } from '../UI/IconButtonToolTip'; import { tooltips } from '../../utils/Constants'; import { useState } from 'react'; import { RiChatSettingsLine } from 'react-icons/ri'; diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 4bde5a9b4..8f42202e4 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -32,6 +32,7 @@ import DeletePopUp from './Popups/DeletePopUp/DeletePopUp'; import GraphEnhancementDialog from './Popups/GraphEnhancementDialog'; import { tokens } from '@neo4j-ndl/base'; import axios from 'axios'; +import DatabaseStatusIcon from './UI/DatabaseIcon'; const ConnectionModal = lazy(() => import('./Popups/ConnectionModal/ConnectionModal')); const ConfirmationDialog = lazy(() => import('./Popups/LargeFilePopUp/ConfirmationDialog')); @@ -86,6 +87,7 @@ const Content: React.FC = ({ alertType: 'error', alertMessage: '', }); + const isGdsActive = true; const { updateStatusForLargeFiles } = useServerSideEvent( (inMinutes, time, fileName) => { setalertDetails({ @@ -651,6 +653,8 @@ const Content: React.FC = ({ } }; + console.log('isGds', isGdsActive); + return ( <> {alertDetails.showAlert && ( @@ -711,16 +715,14 @@ const Content: React.FC = ({ chunksExistsWithDifferentEmbedding={openConnection.chunksExistsWithDifferentDimension} />
-
Neo4j connection - {!connectionStatus ? : } - {connectionStatus ? ( - {userCredentials?.uri} - ) : ( - Not Connected - )} +
{!isSchema ? ( diff --git a/frontend/src/components/DataSources/Local/DropZone.tsx b/frontend/src/components/DataSources/Local/DropZone.tsx index 63ff08e37..d0bf429a5 100644 --- a/frontend/src/components/DataSources/Local/DropZone.tsx +++ b/frontend/src/components/DataSources/Local/DropZone.tsx @@ -8,7 +8,7 @@ import CustomAlert from '../../UI/Alert'; import { CustomFile, CustomFileBase, UserCredentials, alertStateType } from '../../../types'; import { buttonCaptions, chunkSize } from '../../../utils/Constants'; import { InformationCircleIconOutline } from '@neo4j-ndl/react/icons'; -import IconButtonWithToolTip from '../../UI/IconButtonToolTip'; +import { IconButtonWithToolTip } from '../../UI/IconButtonToolTip'; import { uploadAPI } from '../../../utils/FileAPI'; const DropZone: FunctionComponent = () => { diff --git a/frontend/src/components/FileTable.tsx b/frontend/src/components/FileTable.tsx index 23310eaf4..9dad8b18d 100644 --- a/frontend/src/components/FileTable.tsx +++ b/frontend/src/components/FileTable.tsx @@ -45,7 +45,7 @@ import useServerSideEvent from '../hooks/useSse'; import { AxiosError } from 'axios'; import { XMarkIconOutline } from '@neo4j-ndl/react/icons'; import cancelAPI from '../services/CancelAPI'; -import IconButtonWithToolTip from './UI/IconButtonToolTip'; +import { IconButtonWithToolTip } from './UI/IconButtonToolTip'; import { batchSize, largeFileSize, llms } from '../utils/Constants'; import IndeterminateCheckbox from './UI/CustomCheckBox'; let onlyfortheFirstRender = true; diff --git a/frontend/src/components/Graph/GraphViewModal.tsx b/frontend/src/components/Graph/GraphViewModal.tsx index 39438b788..07f276e3f 100644 --- a/frontend/src/components/Graph/GraphViewModal.tsx +++ b/frontend/src/components/Graph/GraphViewModal.tsx @@ -30,7 +30,7 @@ import { MagnifyingGlassMinusIconOutline, MagnifyingGlassPlusIconOutline, } from '@neo4j-ndl/react/icons'; -import IconButtonWithToolTip from '../UI/IconButtonToolTip'; +import { IconButtonWithToolTip } from '../UI/IconButtonToolTip'; import { filterData, processGraphData, sortAlphabetically } from '../../utils/Utils'; import { useCredentials } from '../../context/UserCredentials'; import { LegendsChip } from './LegendsChip'; diff --git a/frontend/src/components/Layout/Header.tsx b/frontend/src/components/Layout/Header.tsx index 345a004fd..acf62eefa 100644 --- a/frontend/src/components/Layout/Header.tsx +++ b/frontend/src/components/Layout/Header.tsx @@ -8,7 +8,7 @@ import { } from '@neo4j-ndl/react/icons'; import { Typography } from '@neo4j-ndl/react'; import { useCallback, useEffect } from 'react'; -import IconButtonWithToolTip from '../UI/IconButtonToolTip'; +import { IconButtonWithToolTip } from '../UI/IconButtonToolTip'; import { tooltips } from '../../utils/Constants'; import { useFileContext } from '../../context/UsersFiles'; diff --git a/frontend/src/components/Layout/SideNav.tsx b/frontend/src/components/Layout/SideNav.tsx index edbfb4d29..bfeb27367 100644 --- a/frontend/src/components/Layout/SideNav.tsx +++ b/frontend/src/components/Layout/SideNav.tsx @@ -17,7 +17,7 @@ import ExpandedChatButtonContainer from '../ChatBot/ExpandedChatButtonContainer' import { APP_SOURCES, tooltips } from '../../utils/Constants'; import ChatModeToggle from '../ChatBot/ChatModeToggle'; import { RiChatSettingsLine } from 'react-icons/ri'; -import IconButtonWithToolTip from '../UI/IconButtonToolTip'; +import { IconButtonWithToolTip } from '../UI/IconButtonToolTip'; import GCSButton from '../DataSources/GCS/GCSButton'; import S3Component from '../DataSources/AWS/S3Bucket'; import WebButton from '../DataSources/Web/WebButton'; diff --git a/frontend/src/components/UI/DatabaseIcon.tsx b/frontend/src/components/UI/DatabaseIcon.tsx new file mode 100644 index 000000000..ae291e401 --- /dev/null +++ b/frontend/src/components/UI/DatabaseIcon.tsx @@ -0,0 +1,25 @@ +import { CircleStackIconOutline, ScienceMoleculeIcon } from '@neo4j-ndl/react/icons'; +import { IconWithToolTip } from './IconButtonToolTip'; +import { DatabaseStatusProps } from '../../types'; +import { connectionLabels } from '../../utils/Constants'; + +const DatabaseStatusIcon: React.FC = ({ isConnected, isGdsActive, uri }) => { + const iconStyle = { fill: 'none', stroke: isConnected ? connectionLabels.greenStroke : connectionLabels.redStroke }; + const text = isGdsActive ? connectionLabels.graphDataScience : connectionLabels.graphDatabase; + return ( +
+ + + {isGdsActive ? ( + + ) : ( + + )} + + + {isConnected ? uri : connectionLabels.notConnected} +
+ ); +}; + +export default DatabaseStatusIcon; diff --git a/frontend/src/components/UI/IconButtonToolTip.tsx b/frontend/src/components/UI/IconButtonToolTip.tsx index 62f438005..160c77b87 100644 --- a/frontend/src/components/UI/IconButtonToolTip.tsx +++ b/frontend/src/components/UI/IconButtonToolTip.tsx @@ -1,6 +1,6 @@ import { IconButton, Tip } from '@neo4j-ndl/react'; -const IconButtonWithToolTip = ({ +export const IconButtonWithToolTip = ({ text, children, onClick, @@ -42,4 +42,27 @@ const IconButtonWithToolTip = ({ ); }; -export default IconButtonWithToolTip; +export const IconWithToolTip = ({ + text, + children, + placement = 'bottom', +}: { + label: string; + text: string | React.ReactNode; + children: React.ReactNode; + onClick?: React.MouseEventHandler | undefined; + size?: 'small' | 'medium' | 'large'; + clean?: boolean; + grouped?: boolean; + placement?: 'bottom' | 'top' | 'right' | 'left'; + disabled?: boolean; +}) => { + return ( + + {children} + + {text} + + + ); +}; diff --git a/frontend/src/components/WebSources/GenericSourceButton.tsx b/frontend/src/components/WebSources/GenericSourceButton.tsx index 65c8b0046..96aab02ff 100644 --- a/frontend/src/components/WebSources/GenericSourceButton.tsx +++ b/frontend/src/components/WebSources/GenericSourceButton.tsx @@ -1,6 +1,6 @@ import { DataComponentProps } from '../../types'; import { Flex, Typography } from '@neo4j-ndl/react'; -import IconButtonWithToolTip from '../UI/IconButtonToolTip'; +import { IconButtonWithToolTip } from '../UI/IconButtonToolTip'; import { InformationCircleIconOutline } from '@neo4j-ndl/react/icons'; import { APP_SOURCES } from '../../utils/Constants'; import WebButton from '../DataSources/Web/WebButton'; diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 5bf076d10..86e54a794 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -648,3 +648,9 @@ export interface MessageContextType { messages: Messages[] | []; setMessages: Dispatch>; } + +export interface DatabaseStatusProps { + isConnected: boolean; + isGdsActive: boolean; + uri: string | null; +} diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index 47f1e119f..7382d3baa 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -236,3 +236,11 @@ export const graphLabels = { }; export const RESULT_STEP_SIZE = 25; + +export const connectionLabels = { + notConnected: 'Not Connected', + graphDataScience: 'Graph Data Science', + graphDatabase: 'Graph Database', + greenStroke: 'green', + redStroke: 'red', +}; From 0c278de458c4d09bce1dc4ac277354a0c21137d3 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Fri, 6 Sep 2024 21:58:44 +0530 Subject: [PATCH 060/292] Add communities check and show respective chat modes (#729) * DataScience icon addition * added checkbox to create_communities * added conditionall check for community chat modes --------- Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> --- .../src/components/ChatBot/ChatModeToggle.tsx | 44 +++++++++++----- frontend/src/components/Content.tsx | 2 +- .../PostProcessingCheckList/index.tsx | 51 ++++++++++--------- frontend/src/context/UserCredentials.tsx | 7 ++- frontend/src/context/UsersFiles.tsx | 1 + frontend/src/types.ts | 2 + frontend/src/utils/Constants.ts | 6 ++- frontend/src/utils/Utils.ts | 7 +++ 8 files changed, 81 insertions(+), 39 deletions(-) diff --git a/frontend/src/components/ChatBot/ChatModeToggle.tsx b/frontend/src/components/ChatBot/ChatModeToggle.tsx index e82dfea4d..ec219898f 100644 --- a/frontend/src/components/ChatBot/ChatModeToggle.tsx +++ b/frontend/src/components/ChatBot/ChatModeToggle.tsx @@ -4,6 +4,7 @@ import { useFileContext } from '../../context/UsersFiles'; import CustomMenu from '../UI/Menu'; import { chatModes } from '../../utils/Constants'; import { capitalize } from '@mui/material'; +import { capitalizeWithPlus } from '../../utils/Utils'; export default function ChatModeToggle({ menuAnchor, @@ -18,7 +19,8 @@ export default function ChatModeToggle({ anchorPortal?: boolean; disableBackdrop?: boolean; }) { - const { setchatMode, chatMode } = useFileContext(); + const { setchatMode, chatMode, postProcessingTasks } = useFileContext(); + const isCommunityAllowed = postProcessingTasks.includes('create_communities'); return ( - chatModes?.map((m) => { + items={useMemo(() => { + if (isCommunityAllowed) { + return chatModes?.map((m) => { return { - title: m.includes('+') - ? m - .split('+') - .map((s) => capitalize(s)) - .join('+') - : capitalize(m), + title: m.includes('+') ? capitalizeWithPlus(m) : capitalize(m), onClick: () => { setchatMode(m); }, @@ -51,9 +48,30 @@ export default function ChatModeToggle({ ), }; - }), - [chatMode, chatModes] - )} + }); + } + return chatModes + ?.filter((s) => !s.includes('community')) + ?.map((m) => { + return { + title: m.includes('+') ? capitalizeWithPlus(m) : capitalize(m), + onClick: () => { + setchatMode(m); + }, + disabledCondition: false, + description: ( + + {chatMode === m && ( + <> + Selected + + )} + + ), + }; + }); + + }, [chatMode, chatModes,isCommunityAllowed])} > ); } diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 8f42202e4..95f632d38 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -59,7 +59,7 @@ const Content: React.FC = ({ const [openGraphView, setOpenGraphView] = useState(false); const [inspectedName, setInspectedName] = useState(''); const [connectionStatus, setConnectionStatus] = useState(false); - const { setUserCredentials, userCredentials } = useCredentials(); + const { setUserCredentials, userCredentials, isGdsActive } = useCredentials(); const [showConfirmationModal, setshowConfirmationModal] = useState(false); const [extractLoading, setextractLoading] = useState(false); diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/index.tsx index 06e76ff8e..57ebe90c4 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/index.tsx @@ -3,11 +3,12 @@ import { POST_PROCESSING_JOBS } from '../../../../utils/Constants'; import { capitalize } from '../../../../utils/Utils'; import { useFileContext } from '../../../../context/UsersFiles'; import { tokens } from '@neo4j-ndl/base'; - +import { useCredentials } from '../../../../context/UserCredentials'; export default function PostProcessingCheckList() { const { breakpoints } = tokens; const tablet = useMediaQuery(`(min-width:${breakpoints.xs}) and (max-width: ${breakpoints.lg})`); const { postProcessingTasks, setPostProcessingTasks } = useFileContext(); + const { isGdsActive } = useCredentials(); return (
@@ -18,29 +19,33 @@ export default function PostProcessingCheckList() { - {POST_PROCESSING_JOBS.map((job, idx) => ( - - - {job.title - .split('_') - .map((s) => capitalize(s)) - .join(' ')} - - } - checked={postProcessingTasks.includes(job.title)} - onChange={(e) => { - if (e.target.checked) { - setPostProcessingTasks((prev) => [...prev, job.title]); - } else { - setPostProcessingTasks((prev) => prev.filter((s) => s !== job.title)); + {POST_PROCESSING_JOBS.map((job, idx) => { + const isCreateCommunities = job.title === 'create_communities'; + return ( + + + {job.title + .split('_') + .map((s) => capitalize(s)) + .join(' ')} + } - }} - > - {job.description} - - ))} + checked={postProcessingTasks.includes(job.title)} + onChange={(e) => { + if (e.target.checked) { + setPostProcessingTasks((prev) => [...prev, job.title]); + } else { + setPostProcessingTasks((prev) => prev.filter((s) => s !== job.title)); + } + }} + disabled={isCreateCommunities && !isGdsActive} // Disable if GDS is not active + /> + {job.description} + + ); + })}
diff --git a/frontend/src/context/UserCredentials.tsx b/frontend/src/context/UserCredentials.tsx index 20ed75ae5..af59e41f4 100644 --- a/frontend/src/context/UserCredentials.tsx +++ b/frontend/src/context/UserCredentials.tsx @@ -1,4 +1,4 @@ -import { createContext, useState, useContext, FunctionComponent, ReactNode } from 'react'; +import { createContext, useState, useContext, FunctionComponent, ReactNode, useReducer } from 'react'; import { ContextProps, UserCredentials } from '../types'; type Props = { @@ -8,6 +8,8 @@ type Props = { export const UserConnection = createContext({ userCredentials: null, setUserCredentials: () => null, + isGdsActive: null, + setGdsActive: () => null, }); export const useCredentials = () => { const userCredentials = useContext(UserConnection); @@ -15,9 +17,12 @@ export const useCredentials = () => { }; const UserCredentialsWrapper: FunctionComponent = (props) => { const [userCredentials, setUserCredentials] = useState(null); + const [isGdsActive, setGdsActive] = useReducer((s) => !s, false); const value = { userCredentials, setUserCredentials, + isGdsActive, + setGdsActive, }; return {props.children}; }; diff --git a/frontend/src/context/UsersFiles.tsx b/frontend/src/context/UsersFiles.tsx index fd3531403..df805504e 100644 --- a/frontend/src/context/UsersFiles.tsx +++ b/frontend/src/context/UsersFiles.tsx @@ -68,6 +68,7 @@ const FileContextProvider: FC = ({ children }) => { 'materialize_text_chunk_similarities', 'enable_hybrid_search_and_fulltext_search_in_bloom', 'materialize_entity_similarities', + 'create_communities', ]); const [processedCount, setProcessedCount] = useState(0); useEffect(() => { diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 86e54a794..0cd584f5d 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -643,6 +643,8 @@ export interface DrawerChatbotProps { export interface ContextProps { userCredentials: UserCredentials | null; setUserCredentials: (UserCredentials: UserCredentials) => void; + isGdsActive: boolean | null; + setGdsActive: () => void; } export interface MessageContextType { messages: Messages[] | []; diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index 7382d3baa..d3fef33fe 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -59,7 +59,7 @@ export const defaultLLM = llms?.includes('openai-gpt-4o') export const chatModes = process.env?.VITE_CHAT_MODES?.trim() != '' ? process.env.VITE_CHAT_MODES?.split(',') - : ['vector', 'graph', 'graph+vector', 'fulltext', 'graph+vector+fulltext']; + : ['vector', 'graph', 'graph+vector', 'fulltext', 'graph+vector+fulltext', 'local community', 'global community']; export const chunkSize = process.env.VITE_CHUNK_SIZE ? parseInt(process.env.VITE_CHUNK_SIZE) : 1 * 1024 * 1024; export const timeperpage = process.env.VITE_TIME_PER_PAGE ? parseInt(process.env.VITE_TIME_PER_PAGE) : 50; export const timePerByte = 0.2; @@ -184,6 +184,10 @@ export const POST_PROCESSING_JOBS: { title: string; description: string }[] = [ semantic meaning. This facilitates tasks like clustering similar entities, identifying duplicates, and performing similarity-based searches.`, }, + { + title: 'create_communities', + description: 'Create Communities identifies and groups similar entities, improving search accuracy and analysis.', + }, ]; export const batchSize: number = parseInt(process.env.VITE_BATCH_SIZE ?? '2'); diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index 0b8b05841..319322d24 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -245,3 +245,10 @@ export const sortAlphabetically = (a: Relationship, b: Relationship) => { const captionTwo = b.caption?.toLowerCase() || ''; return captionOne.localeCompare(captionTwo); }; + +export const capitalizeWithPlus = (s: string) => { + return s + .split('+') + .map((s) => capitalize(s)) + .join('+'); +}; From 7ff05cc10e59e1d6cadf3505534928fd15b68502 Mon Sep 17 00:00:00 2001 From: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Date: Mon, 9 Sep 2024 14:24:07 +0530 Subject: [PATCH 061/292] youtube transcript issue (#736) * Implement GoogleApiYoutubeLoader for youtube transcript * Url encoding issue fixed for youtube URL * Get transcript using YouTubeTranscriptApi --- backend/src/document_sources/youtube.py | 36 +++++++++++++++++++------ backend/src/main.py | 15 ++++++++++- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/backend/src/document_sources/youtube.py b/backend/src/document_sources/youtube.py index df8ad9a92..fce62774d 100644 --- a/backend/src/document_sources/youtube.py +++ b/backend/src/document_sources/youtube.py @@ -1,3 +1,5 @@ +from pathlib import Path +from langchain.docstore.document import Document from langchain_community.document_loaders import YoutubeLoader from pytube import YouTube from youtube_transcript_api import YouTubeTranscriptApi @@ -8,6 +10,9 @@ from langchain_community.document_loaders.youtube import TranscriptFormat from src.shared.constants import YOUTUBE_CHUNK_SIZE_SECONDS from typing import List, Dict, Any +import os +import re +from langchain_community.document_loaders import GoogleApiClient, GoogleApiYoutubeLoader def get_youtube_transcript(youtube_id): try: @@ -55,14 +60,29 @@ def create_youtube_url(url): def get_documents_from_youtube(url): try: - youtube_loader = YoutubeLoader.from_youtube_url(url, - language=["en-US", "en-gb", "en-ca", "en-au","zh-CN", "zh-Hans", "zh-TW", "fr-FR","de-DE","it-IT","ja-JP","pt-BR","ru-RU","es-ES"], - translation = "en", - add_video_info=True, - transcript_format=TranscriptFormat.CHUNKS, - chunk_size_seconds=YOUTUBE_CHUNK_SIZE_SECONDS) - pages = youtube_loader.load() - file_name = YouTube(url).title + match = re.search(r'(?:v=)([0-9A-Za-z_-]{11})\s*',url) + # youtube_loader = YoutubeLoader.from_youtube_url(url, + # language=["en-US", "en-gb", "en-ca", "en-au","zh-CN", "zh-Hans", "zh-TW", "fr-FR","de-DE","it-IT","ja-JP","pt-BR","ru-RU","es-ES"], + # translation = "en", + # add_video_info=True, + # transcript_format=TranscriptFormat.CHUNKS, + # chunk_size_seconds=YOUTUBE_CHUNK_SIZE_SECONDS) + # video_id = parse_qs(urlparse(url).query).get('v') + # cred_path = os.path.join(os.getcwd(),"llm-experiments_credentials.json") + # print(f'Credential file path on youtube.py {cred_path}') + # google_api_client = GoogleApiClient(service_account_path=Path(cred_path)) + # youtube_loader_channel = GoogleApiYoutubeLoader( + # google_api_client=google_api_client, + # video_ids=[video_id[0].strip()], add_video_info=True + # ) + # youtube_transcript = youtube_loader_channel.load() + # pages = youtube_loader.load() + # print(f'youtube page_content: {youtube_transcript[0].page_content}') + # print(f'youtube id: {youtube_transcript[0].metadata["id"]}') + # print(f'youtube title: {youtube_transcript[0].metadata["snippet"]["title"]}') + transcript= get_youtube_combined_transcript(match.group(1)) + file_name = match.group(1)#youtube_transcript[0].metadata["snippet"]["title"] + pages = [Document(page_content=transcript)] return file_name, pages except Exception as e: error_message = str(e) diff --git a/backend/src/main.py b/backend/src/main.py index 5be8286fc..85e0649f7 100644 --- a/backend/src/main.py +++ b/backend/src/main.py @@ -7,6 +7,7 @@ START_FROM_LAST_PROCESSED_POSITION, DELETE_ENTITIES_AND_START_FROM_BEGINNING) from src.shared.schema_extraction import schema_extraction_from_text +from langchain_community.document_loaders import GoogleApiClient, GoogleApiYoutubeLoader from dotenv import load_dotenv from datetime import datetime import logging @@ -140,8 +141,20 @@ def create_source_node_graph_url_youtube(graph, model, source_url, source_type): obj_source_node.created_at = datetime.now() match = re.search(r'(?:v=)([0-9A-Za-z_-]{11})\s*',obj_source_node.url) logging.info(f"match value: {match}") - obj_source_node.file_name = YouTube(obj_source_node.url).title + cred_path = os.path.join(os.getcwd(),"llm-experiments_credentials.json") + print(f'Credential file path {cred_path}') + video_id = parse_qs(urlparse(youtube_url).query).get('v') + print(f'Video Id Youtube: {video_id}') + # google_api_client = GoogleApiClient(service_account_path=Path(cred_path)) + # youtube_loader_channel = GoogleApiYoutubeLoader( + # google_api_client=google_api_client, + # video_ids=[video_id[0].strip()], add_video_info=True + # ) + # youtube_transcript = youtube_loader_channel.load() + + obj_source_node.file_name = match.group(1)#youtube_transcript[0].metadata["snippet"]["title"] transcript= get_youtube_combined_transcript(match.group(1)) + # print(transcript) if transcript==None or len(transcript)==0: message = f"Youtube transcript is not available for : {obj_source_node.file_name}" raise Exception(message) From 13c7bc839ba945454812bf29d88886d68428330d Mon Sep 17 00:00:00 2001 From: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Date: Mon, 9 Sep 2024 14:25:08 +0000 Subject: [PATCH 062/292] added chnages to graph schema --- backend/test_integrationqa.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/backend/test_integrationqa.py b/backend/test_integrationqa.py index 821cc6b5c..b5a50de60 100644 --- a/backend/test_integrationqa.py +++ b/backend/test_integrationqa.py @@ -65,9 +65,9 @@ def test_graph_from_file_local(model_name): def test_graph_from_wikipedia(model_name): """Test graph creation from a Wikipedia page.""" - wiki_query = 'https://en.wikipedia.org/wiki/Ram_Mandir' + wiki_query = 'https://en.wikipedia.org/wiki/Google_DeepMind' source_type = 'Wikipedia' - file_name = "Ram_Mandir" + file_name = "Google_DeepMind" create_source_node_graph_url_wikipedia(graph, model_name, wiki_query, source_type) wiki_result = extract_graph_from_file_Wikipedia(URI, USERNAME, PASSWORD, DATABASE, model_name, file_name, 1, 'en', '', '') @@ -202,7 +202,7 @@ def test_populate_graph_schema_from_text(model): def run_tests(): final_list = [] error_list = [] - models = ['openai-gpt-3.5', 'openai-gpt-4o'] + models = ['openai-gpt-4o','gemini-1.5-pro'] for model_name in models: try: @@ -210,10 +210,10 @@ def run_tests(): final_list.append(test_graph_from_wikipedia(model_name)) final_list.append(test_populate_graph_schema_from_text(model_name)) final_list.append(test_graph_website(model_name)) - final_list.append(test_graph_from_youtube_video(model_name)) - final_list.append(test_chatbot_qna(model_name)) - final_list.append(test_chatbot_qna(model_name, mode='vector')) - final_list.append(test_chatbot_qna(model_name, mode='graph+vector+fulltext')) + # final_list.append(test_graph_from_youtube_video(model_name)) + # final_list.append(test_chatbot_qna(model_name)) + # final_list.append(test_chatbot_qna(model_name, mode='vector')) + # final_list.append(test_chatbot_qna(model_name, mode='graph+vector+fulltext')) except Exception as e: error_list.append((model_name, str(e))) # #Compare and log diffrences in graph results From a12b7cd8f9089f13810a50f4859631edf5ae7b2e Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Tue, 10 Sep 2024 16:52:04 +0000 Subject: [PATCH 063/292] added local search --- backend/score.py | 14 +++--- backend/src/QA_integration.py | 21 ++++---- backend/src/shared/constants.py | 88 ++++++++++++++++++--------------- 3 files changed, 66 insertions(+), 57 deletions(-) diff --git a/backend/score.py b/backend/score.py index 329c8f5b2..6fb245748 100644 --- a/backend/score.py +++ b/backend/score.py @@ -242,13 +242,6 @@ async def post_processing(uri=Form(), userName=Form(), password=Form(), database graph = create_graph_database_connection(uri, userName, password, database) tasks = set(map(str.strip, json.loads(tasks))) - if "create_communities" in tasks: - model = "openai-gpt-4o" - await asyncio.to_thread(create_communities, uri, userName, password, database,model) - josn_obj = {'api_name': 'post_processing/create_communities', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(josn_obj) - logging.info(f'created communities') - if "materialize_text_chunk_similarities" in tasks: await asyncio.to_thread(update_graph, graph) json_obj = {'api_name': 'post_processing/update_similarity_graph', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} @@ -266,6 +259,13 @@ async def post_processing(uri=Form(), userName=Form(), password=Form(), database json_obj = {'api_name': 'post_processing/create_entity_embedding', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} logger.log_struct(json_obj) logging.info(f'Entity Embeddings created') + + if "create_communities" in tasks: + model = "openai-gpt-4o" + await asyncio.to_thread(create_communities, uri, userName, password, database,model) + josn_obj = {'api_name': 'post_processing/create_communities', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(josn_obj) + logging.info(f'created communities') return create_api_response('Success', message='All tasks completed successfully') except Exception as e: diff --git a/backend/src/QA_integration.py b/backend/src/QA_integration.py index 72c1232fa..bdde16a0b 100644 --- a/backend/src/QA_integration.py +++ b/backend/src/QA_integration.py @@ -174,7 +174,7 @@ def format_documents(documents, model): return "\n\n".join(formatted_docs), sources -def process_documents(docs, question, messages, llm, model): +def process_documents(docs, question, messages, llm, model,chat_mode_settings): start_time = time.time() try: @@ -187,8 +187,10 @@ def process_documents(docs, question, messages, llm, model): "context": formatted_docs, "input": question }) - - result = get_sources_and_chunks(sources, docs) + if chat_mode_settings == "local_community_search": + result = {"sources": [], "chunkdetails": []} + else: + result = get_sources_and_chunks(sources, docs) content = ai_response.content total_tokens = get_total_tokens(ai_response, llm) @@ -315,9 +317,10 @@ def create_retriever(neo_db, document_names, chat_mode_settings,search_k, score_ def get_neo4j_retriever(graph, document_names,chat_mode_settings, search_k=CHAT_SEARCH_KWARG_K, score_threshold=CHAT_SEARCH_KWARG_SCORE_THRESHOLD): try: - + neo_db = initialize_neo4j_vector(graph, chat_mode_settings) document_names= list(map(str.strip, json.loads(document_names))) + search_k = LOCAL_COMMUNITY_TOP_K if chat_mode_settings["mode"] == "local_community_search" else CHAT_SEARCH_KWARG_K retriever = create_retriever(neo_db, document_names,chat_mode_settings, search_k, score_threshold) return retriever except Exception as e: @@ -328,8 +331,7 @@ def get_neo4j_retriever(graph, document_names,chat_mode_settings, search_k=CHAT_ def setup_chat(model, graph, document_names, chat_mode_settings): start_time = time.time() try: - if model == "diffbot": - model = "openai-gpt-4o" + model = "openai-gpt-4o" if model == "diffbot" else model llm, model_name = get_llm(model=model) logging.info(f"Model called in chat: {model} (version: {model_name})") @@ -351,9 +353,9 @@ def process_chat_response(messages,history, question, model, graph, document_nam llm, doc_retriever, model_version = setup_chat(model, graph, document_names,chat_mode_settings) docs = retrieve_documents(doc_retriever, messages) - + if docs: - content, result, total_tokens = process_documents(docs, question, messages, llm, model) + content, result, total_tokens = process_documents(docs, question, messages, llm, model,chat_mode_settings) else: content = "I couldn't find any relevant documents to answer your question." result = {"sources": [], "chunkdetails": []} @@ -449,7 +451,6 @@ def create_graph_chain(model, graph): except Exception as e: logging.error(f"An error occurred while creating the GraphCypherQAChain instance. : {e}") - def get_graph_response(graph_chain, question): try: cypher_res = graph_chain.invoke({"query": question}) @@ -471,7 +472,7 @@ def get_graph_response(graph_chain, question): } except Exception as e: - logging.error("An error occurred while getting the graph response : {e}") + logging.error(f"An error occurred while getting the graph response : {e}") def process_graph_response(model, graph, question, messages, history): try: diff --git a/backend/src/shared/constants.py b/backend/src/shared/constants.py index c15602e25..e83f6c8e5 100644 --- a/backend/src/shared/constants.py +++ b/backend/src/shared/constants.py @@ -58,7 +58,7 @@ ## CHAT SETUP CHAT_MAX_TOKENS = 1000 -CHAT_SEARCH_KWARG_K = 3 +CHAT_SEARCH_KWARG_K = 10 CHAT_SEARCH_KWARG_SCORE_THRESHOLD = 0.5 CHAT_DOC_SPLIT_SIZE = 3000 CHAT_EMBEDDING_FILTER_SCORE_THRESHOLD = 0.10 @@ -68,6 +68,13 @@ ("ollama_llama3") : 2 } + +CHAT_TOKEN_CUT_OFF = { + ("openai-gpt-3.5",'azure_ai_gpt_35',"gemini-1.0-pro","gemini-1.5-pro","groq-llama3",'groq_llama3_70b','anthropic_claude_3_5_sonnet','fireworks_llama_v3_70b','bedrock_claude_3_5_sonnet', ) : 4, + ("openai-gpt-4","diffbot" ,'azure_ai_gpt_4o',"openai-gpt-4o", "openai-gpt-4o-mini") : 28, + ("ollama_llama3") : 2 +} + ### CHAT TEMPLATES CHAT_SYSTEM_TEMPLATE = """ You are an AI-powered question-answering agent. Your task is to provide accurate and comprehensive responses to user queries based on the given context, chat history, and available resources. @@ -111,7 +118,6 @@ Note: This system does not generate answers based solely on internal knowledge. It answers from the information provided in the user's current and previous inputs, and from the context. """ - QUESTION_TRANSFORM_TEMPLATE = "Given the below conversation, generate a search query to look up in order to get information relevant to the conversation. Only respond with the query, nothing else." ## CHAT QUERIES @@ -195,59 +201,59 @@ ### Local community search +LOCAL_COMMUNITY_TOP_K = 10 LOCAL_COMMUNITY_TOP_CHUNKS = 3 LOCAL_COMMUNITY_TOP_COMMUNITIES = 3 LOCAL_COMMUNITY_TOP_OUTSIDE_RELS = 10 -LOCAL_COMMUNITY_TOP_INSIDE_RELS = 10 -LOCAL_COMMUNITY_TOP_ENTITIES = 10 LOCAL_COMMUNITY_SEARCH_QUERY = """ -WITH collect(node) as nodes -WITH -collect { +WITH collect(node) as nodes, avg(score) as score +WITH score, +collect {{ UNWIND nodes as n MATCH (n)<-[:HAS_ENTITY]->(c:Chunk) WITH c, count(distinct n) as freq RETURN c.text AS chunkText ORDER BY freq DESC - LIMIT $topChunks -} AS text_mapping, -// Entity - Report Mapping -collect { + LIMIT {topChunks} +}} AS text_mapping, +collect {{ UNWIND nodes as n MATCH (n)-[:IN_COMMUNITY]->(c:__Community__) WITH c, c.rank as rank, c.weight AS weight RETURN c.summary ORDER BY rank, weight DESC - LIMIT $topCommunities -} AS report_mapping, -// Outside Relationships -collect { - UNWIND nodes as n - MATCH (n)-[r:RELATED]-(m) - WHERE NOT m IN nodes - RETURN r.description AS descriptionText - ORDER BY r.rank, r.weight DESC - LIMIT $topOutsideRels -} as outsideRels, -// Inside Relationships -collect { - UNWIND nodes as n - MATCH (n)-[r:RELATED]-(m) - WHERE m IN nodes - RETURN r.description AS descriptionText - ORDER BY r.rank, r.weight DESC - LIMIT $topInsideRels -} as insideRels, -// Entities description -collect { + LIMIT {topCommunities} +}} AS communities, +collect {{ UNWIND nodes as n - RETURN n.description AS descriptionText -} as entities -// We don't have covariates or claims here -RETURN {Chunks: text_mapping, Reports: report_mapping, - Relationships: outsideRels + insideRels, - Entities: entities} AS text, 1.0 AS score, {} AS metadata + RETURN n.id + " " + coalesce(n.description, "") AS descriptionText +}} as entities, +collect {{ + unwind nodes as n + unwind nodes as m + match path = (n)-[r]->(m) + WITH n,r,m + // ORDER BY r.score DESC LIMIT 10 // doesn't exist in ours + WITH distinct r + RETURN startNode(r).id+" "+type(r)+" "+endNode(r).id as relText + // todo should we have a limit here? +}} as rels, +collect {{ + unwind nodes as n + match path = (n)-[r]-(m:__Entity__) + where not m in nodes + with m, collect(distinct r) as rels, count(*) as freq + ORDER BY freq DESC LIMIT {topOutsideRels} + WITH collect(m) as outsideNodes, apoc.coll.flatten(collect(rels)) as rels + RETURN {{nodes: [n in outsideNodes | n.id + " " + coalesce(n.description, "")], + rels: [r in rels | startNode(r).id+" "+type(r)+" "+endNode(r).id]}} +}} as outsideRels + +RETURN {{chunks: text_mapping, communities: communities, + entities: entities, + relationships: rels, + outside: outsideRels}} AS text, score, {{}} AS metadata ; """ CHAT_MODE_CONFIG_MAP= { @@ -264,7 +270,9 @@ "document_filter": False }, "local_community_search": { - "retrieval_query": LOCAL_COMMUNITY_SEARCH_QUERY, + "retrieval_query": LOCAL_COMMUNITY_SEARCH_QUERY.format(topChunks=LOCAL_COMMUNITY_TOP_CHUNKS, + topCommunities=LOCAL_COMMUNITY_TOP_COMMUNITIES, + topOutsideRels=LOCAL_COMMUNITY_TOP_OUTSIDE_RELS), "index_name": "entity_vector", "keyword_index": None, "document_filter": False From 046913863522591b691ac0036c40df4286a66c78 Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Wed, 11 Sep 2024 16:06:15 +0530 Subject: [PATCH 064/292] 725 add checkbox for create communities (#728) * DataScience icon addition * added checkbox to create_communities * added gds status to connect call * added conditionall check for community chat modes * icon stroke changes * isgds active check * icon changes * isGdsVal change * format fixes * checkbox check uncheck change * graph query --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> --- backend/src/shared/constants.py | 17 ++++-- .../src/components/ChatBot/ChatModeToggle.tsx | 54 +++++++++---------- frontend/src/components/Content.tsx | 10 ++-- .../ConnectionModal/ConnectionModal.tsx | 5 +- .../Deduplication/index.tsx | 4 +- .../PostProcessingCheckList/index.tsx | 8 ++- .../src/components/UI/DatabaseStatusIcon.tsx | 26 +++++++++ .../src/components/UI/ScienceMolecule.tsx | 40 ++++++++++++++ frontend/src/context/UserCredentials.tsx | 6 +-- frontend/src/types.ts | 4 +- 10 files changed, 129 insertions(+), 45 deletions(-) create mode 100644 frontend/src/components/UI/DatabaseStatusIcon.tsx create mode 100644 frontend/src/components/UI/ScienceMolecule.tsx diff --git a/backend/src/shared/constants.py b/backend/src/shared/constants.py index c5f8e98a4..a46d1f906 100644 --- a/backend/src/shared/constants.py +++ b/backend/src/shared/constants.py @@ -38,15 +38,26 @@ CALL {{ WITH selectedChunks UNWIND selectedChunks as c - + OPTIONAL MATCH entities=(c:Chunk)-[:HAS_ENTITY]->(e) OPTIONAL MATCH entityRels=(e)--(e2:!Chunk) WHERE exists {{ (e2)<-[:HAS_ENTITY]-(other) WHERE other IN selectedChunks }} - RETURN collect(entities) as entities, collect(entityRels) as entityRels + RETURN entities , entityRels, collect(DISTINCT e) as entity +}} +WITH docs,chunks,chunkRels, collect(entities) as entities, collect(entityRels) as entityRels,entity + +WITH * + +CALL {{ + with entity + unwind entity as n + OPTIONAL MATCH community=(n:__Entity__)-[:IN_COMMUNITY]->(p:__Community__) + OPTIONAL MATCH parentcommunity=(p)-[:PARENT_COMMUNITY]->(p2:__Community__) + return community,parentcommunity }} -WITH apoc.coll.flatten(docs + chunks + chunkRels + entities + entityRels, true) as paths +WITH apoc.coll.flatten(docs + chunks + chunkRels + entities + entityRels + community+ parentcommunity, true) as paths // distinct nodes and rels CALL {{ WITH paths UNWIND paths AS path UNWIND nodes(path) as node WITH distinct node diff --git a/frontend/src/components/ChatBot/ChatModeToggle.tsx b/frontend/src/components/ChatBot/ChatModeToggle.tsx index ec219898f..754a791a4 100644 --- a/frontend/src/components/ChatBot/ChatModeToggle.tsx +++ b/frontend/src/components/ChatBot/ChatModeToggle.tsx @@ -5,7 +5,7 @@ import CustomMenu from '../UI/Menu'; import { chatModes } from '../../utils/Constants'; import { capitalize } from '@mui/material'; import { capitalizeWithPlus } from '../../utils/Utils'; - +import { useCredentials } from '../../context/UserCredentials'; export default function ChatModeToggle({ menuAnchor, closeHandler = () => {}, @@ -21,7 +21,8 @@ export default function ChatModeToggle({ }) { const { setchatMode, chatMode, postProcessingTasks } = useFileContext(); const isCommunityAllowed = postProcessingTasks.includes('create_communities'); - + const { isGdsActive } = useCredentials(); + return ( { - if (isCommunityAllowed) { + if (isGdsActive && isCommunityAllowed) { return chatModes?.map((m) => { return { title: m.includes('+') ? capitalizeWithPlus(m) : capitalize(m), @@ -49,29 +50,28 @@ export default function ChatModeToggle({ ), }; }); - } - return chatModes - ?.filter((s) => !s.includes('community')) - ?.map((m) => { - return { - title: m.includes('+') ? capitalizeWithPlus(m) : capitalize(m), - onClick: () => { - setchatMode(m); - }, - disabledCondition: false, - description: ( - - {chatMode === m && ( - <> - Selected - - )} - - ), - }; - }); - - }, [chatMode, chatModes,isCommunityAllowed])} - > + } + return chatModes + ?.filter((s) => !s.includes('community')) + ?.map((m) => { + return { + title: m.includes('+') ? capitalizeWithPlus(m) : capitalize(m), + onClick: () => { + setchatMode(m); + }, + disabledCondition: false, + description: ( + + {chatMode === m && ( + <> + Selected + + )} + + ), + }; + }); + }, [chatMode, chatModes, isCommunityAllowed, isGdsActive])} + /> ); } diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 95f632d38..a9e66f709 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -32,7 +32,7 @@ import DeletePopUp from './Popups/DeletePopUp/DeletePopUp'; import GraphEnhancementDialog from './Popups/GraphEnhancementDialog'; import { tokens } from '@neo4j-ndl/base'; import axios from 'axios'; -import DatabaseStatusIcon from './UI/DatabaseIcon'; +import DatabaseStatusIcon from './UI/DatabaseStatusIcon'; const ConnectionModal = lazy(() => import('./Popups/ConnectionModal/ConnectionModal')); const ConfirmationDialog = lazy(() => import('./Popups/LargeFilePopUp/ConfirmationDialog')); @@ -59,7 +59,7 @@ const Content: React.FC = ({ const [openGraphView, setOpenGraphView] = useState(false); const [inspectedName, setInspectedName] = useState(''); const [connectionStatus, setConnectionStatus] = useState(false); - const { setUserCredentials, userCredentials, isGdsActive } = useCredentials(); + const { setUserCredentials, userCredentials, isGdsActive, setGdsActive } = useCredentials(); const [showConfirmationModal, setshowConfirmationModal] = useState(false); const [extractLoading, setextractLoading] = useState(false); @@ -87,7 +87,6 @@ const Content: React.FC = ({ alertType: 'error', alertMessage: '', }); - const isGdsActive = true; const { updateStatusForLargeFiles } = useServerSideEvent( (inMinutes, time, fileName) => { setalertDetails({ @@ -128,6 +127,9 @@ const Content: React.FC = ({ database: neo4jConnection.database, port: neo4jConnection.uri.split(':')[2], }); + if (neo4jConnection.isgdsActive !== undefined) { + setGdsActive(neo4jConnection.isgdsActive); + } } else { setOpenConnection((prev) => ({ ...prev, openPopUp: true })); } @@ -653,8 +655,6 @@ const Content: React.FC = ({ } }; - console.log('isGds', isGdsActive); - return ( <> {alertDetails.showAlert && ( diff --git a/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx b/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx index ab9fe2399..f39f392ec 100644 --- a/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx +++ b/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx @@ -41,7 +41,7 @@ export default function ConnectionModal({ const [username, setUsername] = useState(initialusername ?? 'neo4j'); const [password, setPassword] = useState(''); const [connectionMessage, setMessage] = useState({ type: 'unknown', content: '' }); - const { setUserCredentials, userCredentials } = useCredentials(); + const { setUserCredentials, userCredentials, setGdsActive } = useCredentials(); const [isLoading, setIsLoading] = useState(false); const [searchParams, setSearchParams] = useSearchParams(); const [userDbVectorIndex, setUserDbVectorIndex] = useState(initialuserdbvectorindex ?? undefined); @@ -201,6 +201,8 @@ export default function ConnectionModal({ if (response?.data?.status !== 'Success') { throw new Error(response.data.error); } else { + const isgdsActive = response.data.data.gds_status; + setGdsActive(isgdsActive); localStorage.setItem( 'neo4j.connection', JSON.stringify({ @@ -209,6 +211,7 @@ export default function ConnectionModal({ password: password, database: database, userDbVectorIndex, + isgdsActive, }) ); setUserDbVectorIndex(response.data.data.db_vector_dimension); diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx index f5a021e30..36fcff3d1 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx @@ -80,12 +80,12 @@ export default function DeduplicationTab() { const onRemove = (nodeid: string, similarNodeId: string) => { setDuplicateNodes((prev) => { return prev.map((d) => - (d.e.elementId === nodeid + d.e.elementId === nodeid ? { ...d, similar: d.similar.filter((n) => n.elementId != similarNodeId), } - : d) + : d ); }); }; diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/index.tsx index 57ebe90c4..0051fefbf 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/index.tsx @@ -32,7 +32,11 @@ export default function PostProcessingCheckList() { .join(' ')} } - checked={postProcessingTasks.includes(job.title)} + checked={ + isCreateCommunities + ? isGdsActive && postProcessingTasks.includes(job.title) + : postProcessingTasks.includes(job.title) + } onChange={(e) => { if (e.target.checked) { setPostProcessingTasks((prev) => [...prev, job.title]); @@ -40,7 +44,7 @@ export default function PostProcessingCheckList() { setPostProcessingTasks((prev) => prev.filter((s) => s !== job.title)); } }} - disabled={isCreateCommunities && !isGdsActive} // Disable if GDS is not active + disabled={isCreateCommunities && !isGdsActive} /> {job.description}
diff --git a/frontend/src/components/UI/DatabaseStatusIcon.tsx b/frontend/src/components/UI/DatabaseStatusIcon.tsx new file mode 100644 index 000000000..7b159607e --- /dev/null +++ b/frontend/src/components/UI/DatabaseStatusIcon.tsx @@ -0,0 +1,26 @@ +import { CircleStackIconOutline } from '@neo4j-ndl/react/icons'; +import { IconWithToolTip } from './IconButtonToolTip'; +import { DatabaseStatusProps } from '../../types'; +import { connectionLabels } from '../../utils/Constants'; +import ScienceMoleculeIcon from '../UI/ScienceMolecule'; + +const DatabaseStatusIcon: React.FC = ({ isConnected, isGdsActive, uri }) => { + const strokeColour = isConnected ? connectionLabels.greenStroke : connectionLabels.redStroke; + const text = isGdsActive ? connectionLabels.graphDataScience : connectionLabels.graphDatabase; + return ( +
+ + + {isGdsActive ? ( + + ) : ( + + )} + + + {isConnected ? uri : connectionLabels.notConnected} +
+ ); +}; + +export default DatabaseStatusIcon; diff --git a/frontend/src/components/UI/ScienceMolecule.tsx b/frontend/src/components/UI/ScienceMolecule.tsx new file mode 100644 index 000000000..6cd046f14 --- /dev/null +++ b/frontend/src/components/UI/ScienceMolecule.tsx @@ -0,0 +1,40 @@ +import React from 'react'; + +interface ScienceMoleculeIconProps { + currentColour: string; +} + +const ScienceMoleculeIcon: React.FC = ({ currentColour }) => ( + + + + + +); + +export default ScienceMoleculeIcon; diff --git a/frontend/src/context/UserCredentials.tsx b/frontend/src/context/UserCredentials.tsx index af59e41f4..14d5b87de 100644 --- a/frontend/src/context/UserCredentials.tsx +++ b/frontend/src/context/UserCredentials.tsx @@ -8,8 +8,8 @@ type Props = { export const UserConnection = createContext({ userCredentials: null, setUserCredentials: () => null, - isGdsActive: null, - setGdsActive: () => null, + isGdsActive: false, + setGdsActive: () => false, }); export const useCredentials = () => { const userCredentials = useContext(UserConnection); @@ -17,7 +17,7 @@ export const useCredentials = () => { }; const UserCredentialsWrapper: FunctionComponent = (props) => { const [userCredentials, setUserCredentials] = useState(null); - const [isGdsActive, setGdsActive] = useReducer((s) => !s, false); + const [isGdsActive, setGdsActive] = useState(false); const value = { userCredentials, setUserCredentials, diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 0cd584f5d..4e5a03d77 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -643,8 +643,8 @@ export interface DrawerChatbotProps { export interface ContextProps { userCredentials: UserCredentials | null; setUserCredentials: (UserCredentials: UserCredentials) => void; - isGdsActive: boolean | null; - setGdsActive: () => void; + isGdsActive: boolean; + setGdsActive: Dispatch>; } export interface MessageContextType { messages: Messages[] | []; From 177f6c8d345f110396796240cf885a86e173ff37 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Wed, 11 Sep 2024 12:06:19 +0000 Subject: [PATCH 065/292] modified local search query --- backend/src/QA_integration.py | 30 +++++++++++++--------- backend/src/shared/constants.py | 44 +++++++++++++++------------------ 2 files changed, 38 insertions(+), 36 deletions(-) diff --git a/backend/src/QA_integration.py b/backend/src/QA_integration.py index bdde16a0b..ecea7b50b 100644 --- a/backend/src/QA_integration.py +++ b/backend/src/QA_integration.py @@ -117,11 +117,11 @@ def get_sources_and_chunks(sources_used, docs): result = { 'sources': sources_used, - 'chunkdetails': chunkdetails_list + 'chunkdetails': chunkdetails_list, + "entities" : list() } return result - def get_rag_chain(llm, system_template=CHAT_SYSTEM_TEMPLATE): try: question_answering_prompt = ChatPromptTemplate.from_messages( @@ -155,12 +155,15 @@ def format_documents(documents, model): formatted_docs = [] sources = set() + lc_entities = {} for doc in sorted_documents: try: - source = doc.metadata.get('source', 'unknown') + source = doc.metadata.get('source', "unknown") sources.add(source) - + + lc_entities = doc.metadata if 'entities'in doc.metadata.keys() else lc_entities + formatted_doc = ( "Document start\n" f"This Document belongs to the source {source}\n" @@ -172,13 +175,13 @@ def format_documents(documents, model): except Exception as e: logging.error(f"Error formatting document: {e}") - return "\n\n".join(formatted_docs), sources + return "\n\n".join(formatted_docs), sources,lc_entities def process_documents(docs, question, messages, llm, model,chat_mode_settings): start_time = time.time() try: - formatted_docs, sources = format_documents(docs, model) + formatted_docs, sources,lc_entities = format_documents(docs, model) rag_chain = get_rag_chain(llm=llm) @@ -187,8 +190,10 @@ def process_documents(docs, question, messages, llm, model,chat_mode_settings): "context": formatted_docs, "input": question }) - if chat_mode_settings == "local_community_search": - result = {"sources": [], "chunkdetails": []} + if chat_mode_settings["mode"] == "local_community_search": + result = {'sources': list(), + 'chunkdetails': list()} + result.update(lc_entities) else: result = get_sources_and_chunks(sources, docs) content = ai_response.content @@ -352,8 +357,7 @@ def process_chat_response(messages,history, question, model, graph, document_nam try: llm, doc_retriever, model_version = setup_chat(model, graph, document_names,chat_mode_settings) - docs = retrieve_documents(doc_retriever, messages) - + docs = retrieve_documents(doc_retriever, messages) if docs: content, result, total_tokens = process_documents(docs, question, messages, llm, model,chat_mode_settings) else: @@ -374,7 +378,8 @@ def process_chat_response(messages,history, question, model, graph, document_nam "chunkdetails": result["chunkdetails"], "total_tokens": total_tokens, "response_time": 0, - "mode": chat_mode_settings["mode"] + "mode": chat_mode_settings["mode"], + "entities" : result["entities"] }, "user": "chatbot" } @@ -390,7 +395,8 @@ def process_chat_response(messages,history, question, model, graph, document_nam "total_tokens": 0, "response_time": 0, "error": f"{type(e).__name__}: {str(e)}", - "mode": chat_mode_settings["mode"] + "mode": chat_mode_settings["mode"], + "entities": [] }, "user": "chatbot" } diff --git a/backend/src/shared/constants.py b/backend/src/shared/constants.py index e83f6c8e5..f0e9531ef 100644 --- a/backend/src/shared/constants.py +++ b/backend/src/shared/constants.py @@ -207,36 +207,29 @@ LOCAL_COMMUNITY_TOP_OUTSIDE_RELS = 10 LOCAL_COMMUNITY_SEARCH_QUERY = """ -WITH collect(node) as nodes, avg(score) as score -WITH score, +WITH collect(node) as nodes, avg(score) as score, collect({{id: elementId(node), score:score}}) as metadata +WITH score, nodes,metadata, collect {{ UNWIND nodes as n MATCH (n)<-[:HAS_ENTITY]->(c:Chunk) WITH c, count(distinct n) as freq - RETURN c.text AS chunkText + RETURN c ORDER BY freq DESC LIMIT {topChunks} -}} AS text_mapping, +}} AS chunks, collect {{ UNWIND nodes as n MATCH (n)-[:IN_COMMUNITY]->(c:__Community__) WITH c, c.rank as rank, c.weight AS weight - RETURN c.summary + RETURN c ORDER BY rank, weight DESC LIMIT {topCommunities} }} AS communities, -collect {{ - UNWIND nodes as n - RETURN n.id + " " + coalesce(n.description, "") AS descriptionText -}} as entities, collect {{ unwind nodes as n unwind nodes as m - match path = (n)-[r]->(m) - WITH n,r,m - // ORDER BY r.score DESC LIMIT 10 // doesn't exist in ours - WITH distinct r - RETURN startNode(r).id+" "+type(r)+" "+endNode(r).id as relText + match (n)-[r]->(m) + RETURN distinct r // todo should we have a limit here? }} as rels, collect {{ @@ -246,14 +239,17 @@ with m, collect(distinct r) as rels, count(*) as freq ORDER BY freq DESC LIMIT {topOutsideRels} WITH collect(m) as outsideNodes, apoc.coll.flatten(collect(rels)) as rels - RETURN {{nodes: [n in outsideNodes | n.id + " " + coalesce(n.description, "")], - rels: [r in rels | startNode(r).id+" "+type(r)+" "+endNode(r).id]}} -}} as outsideRels - -RETURN {{chunks: text_mapping, communities: communities, - entities: entities, - relationships: rels, - outside: outsideRels}} AS text, score, {{}} AS metadata ; + RETURN {{ nodes: outsideNodes, rels: rels }} +}} as outside + +RETURN {{chunks: [c in chunks | c.text], + communities: [c in communities | c.summary], + entities: [n in nodes | apoc.coll.removeAll(labels(n),["__Entity__"])[0] + ":"+ n.id + " " + coalesce(n.description, "")], + relationships: [r in rels | startNode(r).id+" "+type(r)+" "+endNode(r).id], + outside: {{ + nodes: [n in outside[0].nodes | apoc.coll.removeAll(labels(n),["__Entity__"])[0] + ":"+n.id + " " + coalesce(n.description, "")], + relationships: [r in outside[0].rels | apoc.coll.removeAll(labels(startNode(r)),["__Entity__"])[0] + ":"+startNode(r).id+" "+type(r)+" "+apoc.coll.removeAll(labels(startNode(r)),["__Entity__"])[0] + ":"+endNode(r).id]}} + }} AS text, score, {{entities:metadata}} as metadata """ CHAT_MODE_CONFIG_MAP= { @@ -271,8 +267,8 @@ }, "local_community_search": { "retrieval_query": LOCAL_COMMUNITY_SEARCH_QUERY.format(topChunks=LOCAL_COMMUNITY_TOP_CHUNKS, - topCommunities=LOCAL_COMMUNITY_TOP_COMMUNITIES, - topOutsideRels=LOCAL_COMMUNITY_TOP_OUTSIDE_RELS), + topCommunities=LOCAL_COMMUNITY_TOP_COMMUNITIES, + topOutsideRels=LOCAL_COMMUNITY_TOP_OUTSIDE_RELS), "index_name": "entity_vector", "keyword_index": None, "document_filter": False From 36c9dd3651f6d8823e1d78e7304004b5f1894261 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Wed, 11 Sep 2024 15:25:38 +0000 Subject: [PATCH 066/292] added entity details for chat --- backend/score.py | 4 +- backend/src/chunkid_entities.py | 86 ++++++++++++++++++++------------- backend/src/graph_query.py | 6 +-- backend/src/shared/constants.py | 39 ++++++++++++++- 4 files changed, 95 insertions(+), 40 deletions(-) diff --git a/backend/score.py b/backend/score.py index 6fb245748..ad8ab638e 100644 --- a/backend/score.py +++ b/backend/score.py @@ -306,10 +306,10 @@ async def chat_bot(uri=Form(),model=Form(None),userName=Form(), password=Form(), gc.collect() @app.post("/chunk_entities") -async def chunk_entities(uri=Form(),userName=Form(), password=Form(), chunk_ids=Form(None)): +async def chunk_entities(uri=Form(),userName=Form(), password=Form(), database=Form(), chunk_ids=Form(None),is_entity=Form()): try: logging.info(f"URI: {uri}, Username: {userName}, chunk_ids: {chunk_ids}") - result = await asyncio.to_thread(get_entities_from_chunkids,uri=uri, username=userName, password=password, chunk_ids=chunk_ids) + result = await asyncio.to_thread(get_entities_from_chunkids,uri=uri, username=userName, password=password, database=database,chunk_ids=chunk_ids,is_entity=is_entity) json_obj = {'api_name':'chunk_entities','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} logger.log_struct(json_obj) return create_api_response('Success',data=result) diff --git a/backend/src/chunkid_entities.py b/backend/src/chunkid_entities.py index cdbd358d5..1e7ea197a 100644 --- a/backend/src/chunkid_entities.py +++ b/backend/src/chunkid_entities.py @@ -1,24 +1,6 @@ import logging -from neo4j import graph from src.graph_query import * - -CHUNK_QUERY = """ -match (chunk:Chunk) where chunk.id IN $chunksIds - -MATCH (chunk)-[:PART_OF]->(d:Document) -CALL {WITH chunk -MATCH (chunk)-[:HAS_ENTITY]->(e) -MATCH path=(e)(()-[rels:!HAS_ENTITY&!PART_OF]-()){0,2}(:!Chunk &! Document) -UNWIND rels as r -RETURN collect(distinct r) as rels -} -WITH d, collect(distinct chunk) as chunks, apoc.coll.toSet(apoc.coll.flatten(collect(rels))) as rels -RETURN d as doc, [chunk in chunks | chunk {.*, embedding:null}] as chunks, - [r in rels | {startNode:{element_id:elementId(startNode(r)), labels:labels(startNode(r)), properties:{id:startNode(r).id,description:startNode(r).description}}, - endNode:{element_id:elementId(endNode(r)), labels:labels(endNode(r)), properties:{id:endNode(r).id,description:endNode(r).description}}, - relationship: {type:type(r), element_id:elementId(r)}}] as entities -""" - +from src.shared.constants import * def process_records(records): """ @@ -86,8 +68,31 @@ def process_chunk_data(chunk_data): return chunk_properties except Exception as e: logging.error(f"chunkid_entities module: An error occurred while extracting the Chunk text from records: {e}") - -def get_entities_from_chunkids(uri, username, password, chunk_ids): + +def process_chunkids(driver,chunk_ids): + logging.info(f"Starting graph query process for chunk ids") + chunk_ids_list = chunk_ids.split(",") + records, summary, keys = driver.execute_query(CHUNK_QUERY, chunksIds=chunk_ids_list) + result = process_records(records) + logging.info(f"Nodes and relationships are processed") + result["chunk_data"] = process_chunk_data(records) + logging.info(f"Query process completed successfully for chunk ids") + return result + +def process_entityids(driver,chunk_ids): + logging.info(f"Starting graph query process for entity ids") + entity_ids_list = chunk_ids.split(",") + query_body = LOCAL_COMMUNITY_SEARCH_QUERY.format(topChunks=LOCAL_COMMUNITY_TOP_CHUNKS,topCommunities=LOCAL_COMMUNITY_TOP_COMMUNITIES,topOutsideRels=LOCAL_COMMUNITY_TOP_OUTSIDE_RELS) + query = LOCAL_COMMUNITY_DETAILS_QUERY_PREFIX+ query_body +LOCAL_COMMUNITY_DETAILS_QUERY_SUFFIX + records, summary, keys = driver.execute_query(query, entityIds=entity_ids_list) + result = process_records(records) + logging.info(f"Nodes and relationships are processed") + result["chunk_data"] = process_chunk_data(records) + result["community_data"] = records["communities"] + logging.info(f"Query process completed successfully for chunk ids") + return result + +def get_entities_from_chunkids(uri, username, password, database ,chunk_ids,is_entity=False): """ Retrieve and process nodes and relationships from a graph database given a list of chunk IDs. @@ -101,25 +106,40 @@ def get_entities_from_chunkids(uri, username, password, chunk_ids): dict: A dictionary with 'nodes' and 'relationships' keys containing processed data, or an error message. """ try: - logging.info(f"Starting graph query process for chunk ids") - if chunk_ids: - chunk_ids_list = chunk_ids.split(",") - driver = get_graphDB_driver(uri, username, password) - records, summary, keys = driver.execute_query(CHUNK_QUERY, chunksIds=chunk_ids_list) - result = process_records(records) - logging.info(f"Nodes and relationships are processed") - result["chunk_data"] = process_chunk_data(records) - logging.info(f"Query process completed successfully for chunk ids") + + driver = get_graphDB_driver(uri, username, password,database) + if not is_entity: + if chunk_ids: + result = process_chunkids(driver,chunk_ids) + else: + logging.info(f"chunkid_entities module: No chunk ids are passed") + result = { + "nodes": [], + "relationships": [], + "chunk_data":[] + } return result + if chunk_ids: + result = process_entityids(driver,chunk_ids) else: - logging.info(f"chunkid_entities module: No chunk ids are passed") + logging.info(f"chunkid_entities module: No entity ids are passed") result = { "nodes": [], "relationships": [], - "chunk_data":[] + "chunk_data":[], + "community_data":[] } return result except Exception as e: logging.error(f"chunkid_entities module: An error occurred in get_entities_from_chunkids. Error: {str(e)}") - raise Exception(f"chunkid_entities module: An error occurred in get_entities_from_chunkids. Please check the logs for more details.") from e \ No newline at end of file + raise Exception(f"chunkid_entities module: An error occurred in get_entities_from_chunkids. Please check the logs for more details.") from e + + + +uri = "neo4j+s://demo.neo4jlabs.com" +userName = "persistent" +password = "848345f99c41b3844dc02bb4e6295f3e" +database = "persistent2" +ids = "4:b104b2e7-e2ed-4902-b78b-7ad1518ca04f:23","4:b104b2e7-e2ed-4902-b78b-7ad1518ca04f:224" +get_entities_from_chunkids(uri=uri, username=userName, password=password,database=database,chunk_ids=ids,is_entity=True) \ No newline at end of file diff --git a/backend/src/graph_query.py b/backend/src/graph_query.py index 5468fe2c3..b98dd1aa9 100644 --- a/backend/src/graph_query.py +++ b/backend/src/graph_query.py @@ -8,7 +8,7 @@ # watch("neo4j") -def get_graphDB_driver(uri, username, password): +def get_graphDB_driver(uri, username, password,database="neo4j"): """ Creates and returns a Neo4j database driver instance configured with the provided credentials. @@ -20,9 +20,9 @@ def get_graphDB_driver(uri, username, password): logging.info(f"Attempting to connect to the Neo4j database at {uri}") enable_user_agent = os.environ.get("ENABLE_USER_AGENT", "False").lower() in ("true", "1", "yes") if enable_user_agent: - driver = GraphDatabase.driver(uri, auth=(username, password), user_agent=os.environ.get('NEO4J_USER_AGENT')) + driver = GraphDatabase.driver(uri, auth=(username, password),database=database, user_agent=os.environ.get('NEO4J_USER_AGENT')) else: - driver = GraphDatabase.driver(uri, auth=(username, password)) + driver = GraphDatabase.driver(uri, auth=(username, password),database=database) logging.info("Connection successful") return driver except Exception as e: diff --git a/backend/src/shared/constants.py b/backend/src/shared/constants.py index f0e9531ef..b1f25998e 100644 --- a/backend/src/shared/constants.py +++ b/backend/src/shared/constants.py @@ -56,6 +56,23 @@ """ +CHUNK_QUERY = """ +match (chunk:Chunk) where chunk.id IN $chunksIds + +MATCH (chunk)-[:PART_OF]->(d:Document) +CALL {WITH chunk +MATCH (chunk)-[:HAS_ENTITY]->(e) +MATCH path=(e)(()-[rels:!HAS_ENTITY&!PART_OF]-()){0,2}(:!Chunk &! Document) +UNWIND rels as r +RETURN collect(distinct r) as rels +} +WITH d, collect(distinct chunk) as chunks, apoc.coll.toSet(apoc.coll.flatten(collect(rels))) as rels +RETURN d as doc, [chunk in chunks | chunk {.*, embedding:null}] as chunks, + [r in rels | {startNode:{element_id:elementId(startNode(r)), labels:labels(startNode(r)), properties:{id:startNode(r).id,description:startNode(r).description}}, + endNode:{element_id:elementId(endNode(r)), labels:labels(endNode(r)), properties:{id:endNode(r).id,description:endNode(r).description}}, + relationship: {type:type(r), element_id:elementId(r)}}] as entities +""" + ## CHAT SETUP CHAT_MAX_TOKENS = 1000 CHAT_SEARCH_KWARG_K = 10 @@ -199,7 +216,6 @@ RETURN text, avg_score as score, {{length:size(text), source: COALESCE( CASE WHEN d.url CONTAINS "None" THEN d.fileName ELSE d.url END, d.fileName), chunkdetails: chunkdetails}} AS metadata """ - ### Local community search LOCAL_COMMUNITY_TOP_K = 10 LOCAL_COMMUNITY_TOP_CHUNKS = 3 @@ -241,7 +257,10 @@ WITH collect(m) as outsideNodes, apoc.coll.flatten(collect(rels)) as rels RETURN {{ nodes: outsideNodes, rels: rels }} }} as outside +""" + +LOCAL_COMMUNITY_SEARCH_QUERY_SUFFIX = """ RETURN {{chunks: [c in chunks | c.text], communities: [c in communities | c.summary], entities: [n in nodes | apoc.coll.removeAll(labels(n),["__Entity__"])[0] + ":"+ n.id + " " + coalesce(n.description, "")], @@ -252,6 +271,22 @@ }} AS text, score, {{entities:metadata}} as metadata """ +LOCAL_COMMUNITY_DETAILS_QUERY_PREFIX = """ +UNWIND $entityIds as id +MATCH (node) WHERE elementId(node) = id +WITH node, 1.0 as score +""" + +LOCAL_COMMUNITY_DETAILS_QUERY_SUFFIX = """ +RETURN [chunk in chunks | chunk {.*, embedding:null}] as chunks, +[community in communities | community {.*, embedding:null}] as communities, +[node in nodes+outside[0].nodes | node {.*, label:labels(node),embedding:null}] as nodes, +[r in rels+outside[0].rels | {startNode:{element_id:elementId(startNode(r)), labels:labels(startNode(r)), properties:{id:startNode(r).id,description:startNode(r).description}}, + endNode:{element_id:elementId(endNode(r)), labels:labels(endNode(r)), properties:{id:endNode(r).id,description:endNode(r).description}}, + relationship: {type:type(r), element_id:elementId(r)}}] as entities +""" + + CHAT_MODE_CONFIG_MAP= { "vector": { "retrieval_query": VECTOR_SEARCH_QUERY, @@ -268,7 +303,7 @@ "local_community_search": { "retrieval_query": LOCAL_COMMUNITY_SEARCH_QUERY.format(topChunks=LOCAL_COMMUNITY_TOP_CHUNKS, topCommunities=LOCAL_COMMUNITY_TOP_COMMUNITIES, - topOutsideRels=LOCAL_COMMUNITY_TOP_OUTSIDE_RELS), + topOutsideRels=LOCAL_COMMUNITY_TOP_OUTSIDE_RELS)+LOCAL_COMMUNITY_SEARCH_QUERY_SUFFIX, "index_name": "entity_vector", "keyword_index": None, "document_filter": False From 1aaeab643d5e03d4fb3b1b270b233f42247de64b Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Wed, 11 Sep 2024 15:29:23 +0000 Subject: [PATCH 067/292] modified chunkids --- backend/src/chunkid_entities.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/backend/src/chunkid_entities.py b/backend/src/chunkid_entities.py index 1e7ea197a..84b1d3f5f 100644 --- a/backend/src/chunkid_entities.py +++ b/backend/src/chunkid_entities.py @@ -134,12 +134,3 @@ def get_entities_from_chunkids(uri, username, password, database ,chunk_ids,is_e except Exception as e: logging.error(f"chunkid_entities module: An error occurred in get_entities_from_chunkids. Error: {str(e)}") raise Exception(f"chunkid_entities module: An error occurred in get_entities_from_chunkids. Please check the logs for more details.") from e - - - -uri = "neo4j+s://demo.neo4jlabs.com" -userName = "persistent" -password = "848345f99c41b3844dc02bb4e6295f3e" -database = "persistent2" -ids = "4:b104b2e7-e2ed-4902-b78b-7ad1518ca04f:23","4:b104b2e7-e2ed-4902-b78b-7ad1518ca04f:224" -get_entities_from_chunkids(uri=uri, username=userName, password=password,database=database,chunk_ids=ids,is_entity=True) \ No newline at end of file From ebb4c917106431132c29bb1a881b5259f16f6565 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Wed, 11 Sep 2024 16:25:34 +0000 Subject: [PATCH 068/292] modified chunk_entities --- backend/src/chunkid_entities.py | 84 +++++++++++++++++++++++---------- backend/src/shared/constants.py | 2 +- 2 files changed, 61 insertions(+), 25 deletions(-) diff --git a/backend/src/chunkid_entities.py b/backend/src/chunkid_entities.py index 84b1d3f5f..e6ca8a512 100644 --- a/backend/src/chunkid_entities.py +++ b/backend/src/chunkid_entities.py @@ -69,28 +69,64 @@ def process_chunk_data(chunk_data): except Exception as e: logging.error(f"chunkid_entities module: An error occurred while extracting the Chunk text from records: {e}") -def process_chunkids(driver,chunk_ids): - logging.info(f"Starting graph query process for chunk ids") - chunk_ids_list = chunk_ids.split(",") - records, summary, keys = driver.execute_query(CHUNK_QUERY, chunksIds=chunk_ids_list) - result = process_records(records) - logging.info(f"Nodes and relationships are processed") - result["chunk_data"] = process_chunk_data(records) - logging.info(f"Query process completed successfully for chunk ids") - return result - -def process_entityids(driver,chunk_ids): - logging.info(f"Starting graph query process for entity ids") - entity_ids_list = chunk_ids.split(",") - query_body = LOCAL_COMMUNITY_SEARCH_QUERY.format(topChunks=LOCAL_COMMUNITY_TOP_CHUNKS,topCommunities=LOCAL_COMMUNITY_TOP_COMMUNITIES,topOutsideRels=LOCAL_COMMUNITY_TOP_OUTSIDE_RELS) - query = LOCAL_COMMUNITY_DETAILS_QUERY_PREFIX+ query_body +LOCAL_COMMUNITY_DETAILS_QUERY_SUFFIX - records, summary, keys = driver.execute_query(query, entityIds=entity_ids_list) - result = process_records(records) - logging.info(f"Nodes and relationships are processed") - result["chunk_data"] = process_chunk_data(records) - result["community_data"] = records["communities"] - logging.info(f"Query process completed successfully for chunk ids") - return result +def process_chunkids(driver, chunk_ids): + """ + Processes chunk IDs to retrieve chunk data. + """ + try: + logging.info(f"Starting graph query process for chunk ids: {chunk_ids}") + chunk_ids_list = chunk_ids.split(",") + + records, summary, keys = driver.execute_query(CHUNK_QUERY, chunksIds=chunk_ids_list) + result = process_records(records) + logging.info(f"Nodes and relationships are processed") + + result["chunk_data"] = process_chunk_data(records) + logging.info(f"Query process completed successfully for chunk ids: {chunk_ids}") + return result + except Exception as e: + logging.error(f"chunkid_entities module: Error processing chunk ids: {chunk_ids}. Error: {e}") + raise + +def remove_duplicate_nodes(nodes): + unique_nodes = [] + seen_element_ids = set() + + for node in nodes: + element_id = node['element_id'] + if element_id not in seen_element_ids: + unique_nodes.append(node) + seen_element_ids.add(element_id) + + return unique_nodes + +def process_entityids(driver, chunk_ids): + """ + Processes entity IDs to retrieve local community data. + """ + try: + logging.info(f"Starting graph query process for entity ids: {chunk_ids}") + entity_ids_list = chunk_ids.split(",") + query_body = LOCAL_COMMUNITY_SEARCH_QUERY.format( + topChunks=LOCAL_COMMUNITY_TOP_CHUNKS, + topCommunities=LOCAL_COMMUNITY_TOP_COMMUNITIES, + topOutsideRels=LOCAL_COMMUNITY_TOP_OUTSIDE_RELS + ) + query = LOCAL_COMMUNITY_DETAILS_QUERY_PREFIX + query_body + LOCAL_COMMUNITY_DETAILS_QUERY_SUFFIX + + records, summary, keys = driver.execute_query(query, entityIds=entity_ids_list) + + result = process_records(records) + result["nodes"].extend(records[0]["nodes"]) + result["nodes"] = remove_duplicate_nodes(result["nodes"]) + logging.info(f"Nodes and relationships are processed") + result["chunk_data"] = records[0]["chunks"] + result["community_data"] = records[0]["communities"] + logging.info(f"Query process completed successfully for chunk ids: {chunk_ids}") + return result + except Exception as e: + logging.error(f"chunkid_entities module: Error processing entity ids: {chunk_ids}. Error: {e}") + raise def get_entities_from_chunkids(uri, username, password, database ,chunk_ids,is_entity=False): """ @@ -129,8 +165,8 @@ def get_entities_from_chunkids(uri, username, password, database ,chunk_ids,is_e "chunk_data":[], "community_data":[] } - return result + return result except Exception as e: logging.error(f"chunkid_entities module: An error occurred in get_entities_from_chunkids. Error: {str(e)}") - raise Exception(f"chunkid_entities module: An error occurred in get_entities_from_chunkids. Please check the logs for more details.") from e + raise Exception(f"chunkid_entities module: An error occurred in get_entities_from_chunkids. Please check the logs for more details.") from e \ No newline at end of file diff --git a/backend/src/shared/constants.py b/backend/src/shared/constants.py index b1f25998e..64e1db36f 100644 --- a/backend/src/shared/constants.py +++ b/backend/src/shared/constants.py @@ -280,7 +280,7 @@ LOCAL_COMMUNITY_DETAILS_QUERY_SUFFIX = """ RETURN [chunk in chunks | chunk {.*, embedding:null}] as chunks, [community in communities | community {.*, embedding:null}] as communities, -[node in nodes+outside[0].nodes | node {.*, label:labels(node),embedding:null}] as nodes, +[node in nodes+outside[0].nodes | {element_id:elementId(node), labels:labels(node), properties:{id:node.id,description:node.description}}] as nodes, [r in rels+outside[0].rels | {startNode:{element_id:elementId(startNode(r)), labels:labels(startNode(r)), properties:{id:startNode(r).id,description:startNode(r).description}}, endNode:{element_id:elementId(endNode(r)), labels:labels(endNode(r)), properties:{id:endNode(r).id,description:endNode(r).description}}, relationship: {type:type(r), element_id:elementId(r)}}] as entities From c72962ca8f8892c5c12d124689b990ed18c665ea Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Wed, 11 Sep 2024 23:07:32 +0530 Subject: [PATCH 069/292] Add communities Checkbox to graph viz (#739) * DataScience icon addition * added checkbox to create_communities * added gds status to connect call * added conditionall check for community chat modes * icon stroke changes * isgds active check * icon changes * isGdsVal change * format fixes * checkbox check uncheck change * graph query * checkbox addition * filter logic * filter logic missing checks * updated_graph_query * filter logic optimised * gds active check * handle checkbox show --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> --- backend/src/graph_query.py | 7 +- backend/src/shared/constants.py | 9 ++- .../src/components/ChatBot/ChatModeToggle.tsx | 1 - .../components/Graph/CheckboxSelection.tsx | 14 +++- .../src/components/Graph/GraphViewModal.tsx | 50 +++++++----- frontend/src/types.ts | 3 +- frontend/src/utils/Constants.ts | 42 ++++++---- frontend/src/utils/Utils.ts | 77 +++++++++++++++++-- 8 files changed, 148 insertions(+), 55 deletions(-) diff --git a/backend/src/graph_query.py b/backend/src/graph_query.py index 5468fe2c3..8a8576905 100644 --- a/backend/src/graph_query.py +++ b/backend/src/graph_query.py @@ -61,15 +61,18 @@ def process_node(node): with datetime objects formatted as ISO strings. """ try: + labels = set(node.labels) + labels.discard("__Entity__") + node_element = { "element_id": node.element_id, - "labels": list(node.labels), + "labels": list(labels), "properties": {} } # logging.info(f"Processing node with element ID: {node.element_id}") for key in node: - if key in ["embedding", "text"]: + if key in ["embedding", "text", "summary"]: continue value = node.get(key) if isinstance(value, time.DateTime): diff --git a/backend/src/shared/constants.py b/backend/src/shared/constants.py index a46d1f906..8944714f8 100644 --- a/backend/src/shared/constants.py +++ b/backend/src/shared/constants.py @@ -16,6 +16,7 @@ PROJECT_ID = 'llm-experiments-387609' GRAPH_CHUNK_LIMIT = 50 + #query GRAPH_QUERY = """ MATCH docs = (d:Document) @@ -45,7 +46,7 @@ }} RETURN entities , entityRels, collect(DISTINCT e) as entity }} -WITH docs,chunks,chunkRels, collect(entities) as entities, collect(entityRels) as entityRels,entity +WITH docs,chunks,chunkRels, collect(entities) as entities, collect(entityRels) as entityRels, entity WITH * @@ -53,11 +54,11 @@ with entity unwind entity as n OPTIONAL MATCH community=(n:__Entity__)-[:IN_COMMUNITY]->(p:__Community__) - OPTIONAL MATCH parentcommunity=(p)-[:PARENT_COMMUNITY]->(p2:__Community__) - return community,parentcommunity + OPTIONAL MATCH parentcommunity=(p)-[:PARENT_COMMUNITY*]->(p2:__Community__) + return collect(community) as communities , collect(parentcommunity) as parentCommunities }} -WITH apoc.coll.flatten(docs + chunks + chunkRels + entities + entityRels + community+ parentcommunity, true) as paths +WITH apoc.coll.flatten(docs + chunks + chunkRels + entities + entityRels + communities + parentCommunities, true) as paths // distinct nodes and rels CALL {{ WITH paths UNWIND paths AS path UNWIND nodes(path) as node WITH distinct node diff --git a/frontend/src/components/ChatBot/ChatModeToggle.tsx b/frontend/src/components/ChatBot/ChatModeToggle.tsx index 754a791a4..6315394af 100644 --- a/frontend/src/components/ChatBot/ChatModeToggle.tsx +++ b/frontend/src/components/ChatBot/ChatModeToggle.tsx @@ -22,7 +22,6 @@ export default function ChatModeToggle({ const { setchatMode, chatMode, postProcessingTasks } = useFileContext(); const isCommunityAllowed = postProcessingTasks.includes('create_communities'); const { isGdsActive } = useCredentials(); - return ( = ({ graphType, loading, handleChange }) => ( +import { graphLabels } from '../../utils/Constants'; + +const CheckboxSelection: React.FC = ({ graphType, loading, handleChange, isgds }) => (
handleChange('DocumentChunk')} /> handleChange('Entities')} /> + {isgds && ( handleChange('Communities')} + />)}
); diff --git a/frontend/src/components/Graph/GraphViewModal.tsx b/frontend/src/components/Graph/GraphViewModal.tsx index 07f276e3f..8e8cb5c87 100644 --- a/frontend/src/components/Graph/GraphViewModal.tsx +++ b/frontend/src/components/Graph/GraphViewModal.tsx @@ -58,17 +58,17 @@ const GraphViewModal: React.FunctionComponent = ({ const nvlRef = useRef(null); const [nodes, setNodes] = useState([]); const [relationships, setRelationships] = useState([]); - const [graphType, setGraphType] = useState(intitalGraphType); const [allNodes, setAllNodes] = useState([]); const [allRelationships, setAllRelationships] = useState([]); const [loading, setLoading] = useState(false); const [status, setStatus] = useState<'unknown' | 'success' | 'danger'>('unknown'); const [statusMessage, setStatusMessage] = useState(''); - const { userCredentials } = useCredentials(); + const { userCredentials, isGdsActive } = useCredentials(); const [scheme, setScheme] = useState({}); const [newScheme, setNewScheme] = useState({}); const [searchQuery, setSearchQuery] = useState(''); const debouncedQuery = useDebounce(searchQuery, 300); + const [graphType, setGraphType] = useState(intitalGraphType(isGdsActive)); // the checkbox selection const handleCheckboxChange = (graph: GraphType) => { @@ -97,10 +97,10 @@ const GraphViewModal: React.FunctionComponent = ({ graphType.includes('DocumentChunk') && graphType.includes('Entities') ? queryMap.DocChunkEntities : graphType.includes('DocumentChunk') - ? queryMap.DocChunks - : graphType.includes('Entities') - ? queryMap.Entities - : ''; + ? queryMap.DocChunks + : graphType.includes('Entities') + ? queryMap.Entities + : ''; // fit graph to original position const handleZoomToFit = () => { @@ -119,7 +119,7 @@ const GraphViewModal: React.FunctionComponent = ({ if (nvlRef.current) { nvlRef.current?.destroy(); } - setGraphType(intitalGraphType); + setGraphType(intitalGraphType(isGdsActive)); clearTimeout(timeoutId); setScheme({}); setNodes([]); @@ -135,10 +135,10 @@ const GraphViewModal: React.FunctionComponent = ({ const nodeRelationshipData = viewPoint === graphLabels.showGraphView ? await graphQueryAPI( - userCredentials as UserCredentials, - graphQuery, - selectedRows?.map((f) => f.name) - ) + userCredentials as UserCredentials, + graphQuery, + selectedRows?.map((f) => f.name) + ) : await graphQueryAPI(userCredentials as UserCredentials, graphQuery, [inspectedName ?? '']); return nodeRelationshipData; } catch (error: any) { @@ -180,6 +180,7 @@ const GraphViewModal: React.FunctionComponent = ({ useEffect(() => { if (open) { setLoading(true); + setGraphType(intitalGraphType(isGdsActive)) if (viewPoint !== 'chatInfoView') { graphApi(); } else { @@ -193,7 +194,7 @@ const GraphViewModal: React.FunctionComponent = ({ setLoading(false); } } - }, [open]); + }, [open, isGdsActive]); // The search and update nodes const handleSearch = useCallback( @@ -219,8 +220,8 @@ const GraphViewModal: React.FunctionComponent = ({ match && viewPoint === graphLabels.showGraphView ? 100 : match && viewPoint !== graphLabels.showGraphView - ? 50 - : graphLabels.nodeSize, + ? 50 + : graphLabels.nodeSize, }; }); // deactivating any active relationships @@ -252,7 +253,8 @@ const GraphViewModal: React.FunctionComponent = ({ graphType, finalNodes ?? [], finalRels ?? [], - schemeVal + schemeVal, + isGdsActive ); setNodes(filteredNodes); setRelationships(filteredRelations); @@ -305,7 +307,7 @@ const GraphViewModal: React.FunctionComponent = ({ setStatusMessage(''); setGraphViewOpen(false); setScheme({}); - setGraphType(intitalGraphType); + setGraphType(intitalGraphType(isGdsActive)); setNodes([]); setRelationships([]); setAllNodes([]); @@ -351,8 +353,8 @@ const GraphViewModal: React.FunctionComponent = ({ isActive && viewPoint === graphLabels.showGraphView ? 100 : isActive && viewPoint !== graphLabels.showGraphView - ? 50 - : graphLabels.nodeSize, + ? 50 + : graphLabels.nodeSize, }; }); // deactivating any active relationships @@ -394,6 +396,9 @@ const GraphViewModal: React.FunctionComponent = ({ setNodes(updatedNodes); }; + console.log('rels', relationships); + + console.log('nodes', nodes); return ( <> = ({ {headerTitle} {checkBoxView && ( - + )} @@ -427,7 +437,7 @@ const GraphViewModal: React.FunctionComponent = ({
) : nodes.length === 0 && relationships.length === 0 && graphType.length !== 0 ? (
- +
) : graphType.length === 0 ? (
diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 4e5a03d77..4fb5361f2 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -263,7 +263,7 @@ export interface GraphViewModalProps { selectedRows?: CustomFile[] | undefined; } -export type GraphType = 'Entities' | 'DocumentChunk'; +export type GraphType = 'Entities' | 'DocumentChunk' | 'Communities'; export type PartialLabelNode = Partial & { labels: string; @@ -273,6 +273,7 @@ export interface CheckboxSectionProps { graphType: GraphType[]; loading: boolean; handleChange: (graph: GraphType) => void; + isgds: boolean; } export interface fileName { diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index d3fef33fe..e6b11e798 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -36,26 +36,26 @@ export const llms = process.env?.VITE_LLM_MODELS?.trim() != '' ? (process.env.VITE_LLM_MODELS?.split(',') as string[]) : [ - 'diffbot', - 'openai-gpt-3.5', - 'openai-gpt-4o', - 'openai-gpt-4o-mini', - 'gemini-1.0-pro', - 'gemini-1.5-pro', - 'azure_ai_gpt_35', - 'azure_ai_gpt_4o', - 'ollama_llama3', - 'groq_llama3_70b', - 'anthropic_claude_3_5_sonnet', - 'fireworks_v3p1_405b', - 'bedrock_claude_3_5_sonnet', - ]; + 'diffbot', + 'openai-gpt-3.5', + 'openai-gpt-4o', + 'openai-gpt-4o-mini', + 'gemini-1.0-pro', + 'gemini-1.5-pro', + 'azure_ai_gpt_35', + 'azure_ai_gpt_4o', + 'ollama_llama3', + 'groq_llama3_70b', + 'anthropic_claude_3_5_sonnet', + 'fireworks_v3p1_405b', + 'bedrock_claude_3_5_sonnet', + ]; export const defaultLLM = llms?.includes('openai-gpt-4o') ? 'openai-gpt-4o' : llms?.includes('gemini-1.0-pro') - ? 'gemini-1.0-pro' - : 'diffbot'; + ? 'gemini-1.0-pro' + : 'diffbot'; export const chatModes = process.env?.VITE_CHAT_MODES?.trim() != '' ? process.env.VITE_CHAT_MODES?.split(',') @@ -215,7 +215,12 @@ export const graphView: OptionType[] = [ { label: 'Entity Graph', value: queryMap.Entities }, { label: 'Knowledge Graph', value: queryMap.DocChunkEntities }, ]; -export const intitalGraphType: GraphType[] = ['DocumentChunk', 'Entities']; + +export const intitalGraphType = (isGDSActive: boolean): GraphType[] => { + return isGDSActive + ? ['DocumentChunk', 'Entities', 'Communities'] // GDS is active, include communities + : ['DocumentChunk', 'Entities']; // GDS is inactive, exclude communities +}; export const appLabels = { ownSchema: 'Or Define your own Schema', @@ -237,6 +242,9 @@ export const graphLabels = { selectCheckbox: 'Select atleast one checkbox for graph view', totalRelationships: 'Total Relationships', nodeSize: 30, + docChunk: 'Document & Chunk', + community: 'Communities', + noNodesRels: 'No Nodes and No relationships', }; export const RESULT_STEP_SIZE = 25; diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index 319322d24..28b176e49 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -166,18 +166,28 @@ export const processGraphData = (neoNodes: ExtendedNode[], neoRels: ExtendedRela return { finalNodes, finalRels, schemeVal }; }; +/** +* Filters nodes, relationships, and scheme based on the selected graph types. +* +* @param graphType - An array of graph types to filter by (e.g., 'DocumentChunk', 'Entities', 'Communities'). +* @param allNodes - An array of all nodes present in the graph. +* @param allRelationships - An array of all relationships in the graph. +* @param scheme - The scheme object containing node and relationship information. +* @returns An object containing filtered nodes, relationships, and scheme based on the selected graph types. +*/ export const filterData = ( graphType: GraphType[], allNodes: ExtendedNode[], allRelationships: Relationship[], - scheme: Scheme + scheme: Scheme, + isGdsActive: boolean, ) => { let filteredNodes: ExtendedNode[] = []; let filteredRelations: Relationship[] = []; let filteredScheme: Scheme = {}; - const entityTypes = Object.keys(scheme).filter((type) => type !== 'Document' && type !== 'Chunk'); - if (graphType.includes('DocumentChunk') && !graphType.includes('Entities')) { - // Document + Chunk + const entityTypes = Object.keys(scheme).filter((type) => type !== 'Document' && type !== 'Chunk' && type !== '__Community__'); + // Only Document + Chunk + if (graphType.includes('DocumentChunk') && !graphType.includes('Entities') && (!graphType.includes('Communities') || !isGdsActive)) { filteredNodes = allNodes.filter( (node) => (node.labels.includes('Document') && node.properties.fileName) || node.labels.includes('Chunk') ); @@ -189,8 +199,8 @@ export const filterData = ( nodeIds.has(rel.to) ); filteredScheme = { Document: scheme.Document, Chunk: scheme.Chunk }; - } else if (graphType.includes('Entities') && !graphType.includes('DocumentChunk')) { // Only Entity + } else if (graphType.includes('Entities') && !graphType.includes('DocumentChunk') && (!graphType.includes('Communities') || !isGdsActive)) { const entityNodes = allNodes.filter((node) => !node.labels.includes('Document') && !node.labels.includes('Chunk')); filteredNodes = entityNodes ? entityNodes : []; const nodeIds = new Set(filteredNodes.map((node) => node.id)); @@ -201,15 +211,68 @@ export const filterData = ( nodeIds.has(rel.to) ); filteredScheme = Object.fromEntries(entityTypes.map((key) => [key, scheme[key]])) as Scheme; - } else if (graphType.includes('DocumentChunk') && graphType.includes('Entities')) { + // Only Communities + } else if (graphType.includes('Communities') && !graphType.includes('DocumentChunk') && !graphType.includes('Entities') && isGdsActive) { + filteredNodes = allNodes.filter((node) => node.labels.includes('__Community__')); + const nodeIds = new Set(filteredNodes.map((node) => node.id)); + filteredRelations = allRelationships.filter( + (rel) => + ['IN_COMMUNITY', 'PARENT_COMMUNITY'].includes(rel.caption ?? '') && nodeIds.has(rel.from) && nodeIds.has(rel.to) + ); + filteredScheme = { __Community__: scheme.__Community__ }; // Document + Chunk + Entity + } else if (graphType.includes('DocumentChunk') && graphType.includes('Entities') && (!graphType.includes('Communities') || !isGdsActive)) { + filteredNodes = allNodes.filter( + (node) => + (node.labels.includes('Document') && node.properties.fileName) || node.labels.includes('Chunk') || !node.labels.includes('Document') && !node.labels.includes('Chunk') && !node.labels.includes('__Community__') + ); + const nodeIds = new Set(filteredNodes.map((node) => node.id)); + filteredRelations = allRelationships.filter( + (rel) => + !['IN_COMMUNITY', 'PARENT_COMMUNITY'].includes(rel.caption ?? '') && + nodeIds.has(rel.from) && + nodeIds.has(rel.to) + ); + filteredScheme = { Document: scheme.Document, Chunk: scheme.Chunk, ...Object.fromEntries(entityTypes.map((key) => [key, scheme[key]])) }; + // Entities + Communities + } else if (graphType.includes('Entities') && graphType.includes('Communities') && !graphType.includes('DocumentChunk') && isGdsActive) { + const entityNodes = allNodes.filter((node) => !node.labels.includes('Document') && !node.labels.includes('Chunk')); + const communityNodes = allNodes.filter((node) => node.labels.includes('__Community__')); + filteredNodes = [...entityNodes, ...communityNodes]; + const nodeIds = new Set(filteredNodes.map((node) => node.id)); + filteredRelations = allRelationships.filter( + (rel) => + !['PART_OF', 'FIRST_CHUNK', 'SIMILAR', 'NEXT_CHUNK'].includes(rel.caption ?? '') && + nodeIds.has(rel.from) && + nodeIds.has(rel.to) + ); + filteredScheme = { + ...Object.fromEntries(entityTypes.map((key) => [key, scheme[key]])), + __Community__: scheme.__Community__ + }; + // Document + Chunk + Communities + } else if (graphType.includes('DocumentChunk') && graphType.includes('Communities') && !graphType.includes('Entities') && isGdsActive) { + const documentChunkNodes = allNodes.filter( + (node) => (node.labels.includes('Document') && node.properties.fileName) || node.labels.includes('Chunk') + ); + const communityNodes = allNodes.filter((node) => node.labels.includes('__Community__')); + filteredNodes = [...documentChunkNodes, ...communityNodes]; + const nodeIds = new Set(filteredNodes.map((node) => node.id)); + filteredRelations = allRelationships.filter( + (rel) => + ['PART_OF', 'FIRST_CHUNK', 'SIMILAR', 'NEXT_CHUNK', 'IN_COMMUNITY', 'PARENT_COMMUNITY'].includes(rel.caption ?? '') && + nodeIds.has(rel.from) && + nodeIds.has(rel.to) + ); + filteredScheme = { Document: scheme.Document, Chunk: scheme.Chunk, __Community__: scheme.__Community__ }; + // Document + Chunk + Entity + Communities (All types) + } else if (graphType.includes('DocumentChunk') && graphType.includes('Entities') && graphType.includes('Communities') && isGdsActive) { filteredNodes = allNodes; filteredRelations = allRelationships; filteredScheme = scheme; } return { filteredNodes, filteredRelations, filteredScheme }; }; - export const getDateTime = () => { const date = new Date(); const formattedDateTime = `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`; From 2d4c35a2214d3a8194e557e99a7aeffa9aa032fc Mon Sep 17 00:00:00 2001 From: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Date: Thu, 12 Sep 2024 07:09:48 +0000 Subject: [PATCH 070/292] Added time to process file in extract API and it's functions --- backend/score.py | 3 +++ backend/src/main.py | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/backend/score.py b/backend/score.py index 52bd166bb..f20790cc4 100644 --- a/backend/score.py +++ b/backend/score.py @@ -154,6 +154,7 @@ async def extract_knowledge_graph_from_file( Nodes and Relations created in Neo4j databse for the pdf file """ try: + start_time = time.time() graph = create_graph_database_connection(uri, userName, password, database) graphDb_data_Access = graphDBdataAccess(graph) @@ -193,6 +194,8 @@ async def extract_knowledge_graph_from_file( result['source_type'] = source_type result['logging_time'] = formatted_time(datetime.now(timezone.utc)) logger.log_struct(result) + extract_api_time = time.time() - start_time + logging.info(f"extraction completed in {extract_api_time:.2f} seconds for file name {file_name}") return create_api_response('Success', data=result, file_source= source_type) except Exception as e: message=f"Failed To Process File:{file_name} or LLM Unable To Parse Content " diff --git a/backend/src/main.py b/backend/src/main.py index 85e0649f7..cc5569c0d 100644 --- a/backend/src/main.py +++ b/backend/src/main.py @@ -281,6 +281,7 @@ def processing_source(uri, userName, password, database, model, file_name, pages status and model as attributes. """ start_time = datetime.now() + processing_source_start_time = time.time() graph = create_graph_database_connection(uri, userName, password, database) graphDb_data_Access = graphDBdataAccess(graph) @@ -329,7 +330,10 @@ def processing_source(uri, userName, password, database, model, file_name, pages logging.info('Exit from running loop of processing file') break else: + processing_chunks_start_time = time.time() node_count,rel_count = processing_chunks(selected_chunks,graph,uri, userName, password, database,file_name,model,allowedNodes,allowedRelationship,node_count, rel_count) + processing_chunks_end_time = time.time() - processing_chunks_start_time + logging.info(f"{update_graph_chunk_processed} chunks processed upto {select_chunks_upto} completed in {processing_chunks_end_time:.2f} seconds for file name {file_name}") end_time = datetime.now() processed_time = end_time - start_time @@ -369,7 +373,8 @@ def processing_source(uri, userName, password, database, model, file_name, pages delete_file_from_gcs(BUCKET_UPLOAD,folder_name,file_name) else: delete_uploaded_local_file(merged_file_path, file_name) - + processing_source_func = time.time() - processing_source_start_time + logging.info(f"processing source function completed in {processing_source_func:.2f} seconds for file name {file_name}") return { "fileName": file_name, "nodeCount": node_count, From 29205dc6f88c2df8818aa4ac61e4a514ea1d021d Mon Sep 17 00:00:00 2001 From: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Date: Thu, 12 Sep 2024 07:45:45 +0000 Subject: [PATCH 071/292] Add Severity level in cloud logging --- backend/score.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/backend/score.py b/backend/score.py index f20790cc4..ca3707ce1 100644 --- a/backend/score.py +++ b/backend/score.py @@ -193,7 +193,7 @@ async def extract_knowledge_graph_from_file( result['wiki_query'] = wiki_query result['source_type'] = source_type result['logging_time'] = formatted_time(datetime.now(timezone.utc)) - logger.log_struct(result) + logger.log_struct({"severity":"INFO","jsonPayload":result}) extract_api_time = time.time() - start_time logging.info(f"extraction completed in {extract_api_time:.2f} seconds for file name {file_name}") return create_api_response('Success', data=result, file_source= source_type) @@ -212,7 +212,7 @@ async def extract_knowledge_graph_from_file( logging.info(f'Deleted File Path: {merged_file_path} and Deleted File Name : {file_name}') delete_uploaded_local_file(merged_file_path,file_name) json_obj = {'message':message,'error_message':error_message, 'file_name': file_name,'status':'Failed','db_url':uri,'failed_count':1, 'source_type': source_type, 'source_url':source_url, 'wiki_query':wiki_query, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(json_obj) + logger.log_struct({"severity":"ERROR","jsonPayload":json_obj}) logging.exception(f'File Failed in extraction: {json_obj}') return create_api_response('Failed', message=message + error_message[:100], error=error_message, file_name = file_name) finally: @@ -229,7 +229,7 @@ async def get_source_list(uri:str, userName:str, password:str, database:str=None uri = uri.replace(" ","+") result = await asyncio.to_thread(get_source_list_from_graph,uri,userName,decoded_password,database) json_obj = {'api_name':'sources_list','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(json_obj) + logger.log_struct({"severity":"INFO","jsonPayload":json_obj}) return create_api_response("Success",data=result) except Exception as e: job_status = "Failed" @@ -243,24 +243,23 @@ async def post_processing(uri=Form(), userName=Form(), password=Form(), database try: graph = create_graph_database_connection(uri, userName, password, database) tasks = set(map(str.strip, json.loads(tasks))) - + if "materialize_text_chunk_similarities" in tasks: await asyncio.to_thread(update_graph, graph) json_obj = {'api_name': 'post_processing/update_similarity_graph', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(json_obj) logging.info(f'Updated KNN Graph') if "enable_hybrid_search_and_fulltext_search_in_bloom" in tasks: await asyncio.to_thread(create_fulltext, uri=uri, username=userName, password=password, database=database,type="entities") # await asyncio.to_thread(create_fulltext, uri=uri, username=userName, password=password, database=database,type="keyword") - josn_obj = {'api_name': 'post_processing/enable_hybrid_search_and_fulltext_search_in_bloom', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(josn_obj) + json_obj = {'api_name': 'post_processing/enable_hybrid_search_and_fulltext_search_in_bloom', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} logging.info(f'Full Text index created') if os.environ.get('ENTITY_EMBEDDING','False').upper()=="TRUE" and "materialize_entity_similarities" in tasks: await asyncio.to_thread(create_entity_embedding, graph) json_obj = {'api_name': 'post_processing/create_entity_embedding', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(json_obj) logging.info(f'Entity Embeddings created') + + logger.log_struct({"severity":"INFO","jsonPayload":json_obj}) return create_api_response('Success', message='All tasks completed successfully') except Exception as e: @@ -289,7 +288,8 @@ async def chat_bot(uri=Form(),model=Form(None),userName=Form(), password=Form(), result["info"]["response_time"] = round(total_call_time, 2) json_obj = {'api_name':'chat_bot','db_url':uri,'session_id':session_id, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(json_obj) + logger.log_struct({"severity":"INFO","jsonPayload":json_obj}) + return create_api_response('Success',data=result) except Exception as e: job_status = "Failed" @@ -306,7 +306,7 @@ async def chunk_entities(uri=Form(),userName=Form(), password=Form(), chunk_ids= logging.info(f"URI: {uri}, Username: {userName}, chunk_ids: {chunk_ids}") result = await asyncio.to_thread(get_entities_from_chunkids,uri=uri, username=userName, password=password, chunk_ids=chunk_ids) json_obj = {'api_name':'chunk_entities','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(json_obj) + logger.log_struct({"severity":"INFO","jsonPayload":json_obj}) return create_api_response('Success',data=result) except Exception as e: job_status = "Failed" @@ -334,7 +334,7 @@ async def graph_query( document_names=document_names ) json_obj = {'api_name':'graph_query','db_url':uri,'document_names':document_names, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(json_obj) + logger.log_struct({"severity":"INFO","jsonPayload":json_obj}) return create_api_response('Success', data=result) except Exception as e: job_status = "Failed" @@ -367,7 +367,7 @@ async def connect(uri=Form(), userName=Form(), password=Form(), database=Form()) graph = create_graph_database_connection(uri, userName, password, database) result = await asyncio.to_thread(connection_check_and_get_vector_dimensions, graph) json_obj = {'api_name':'connect','db_url':uri,'status':result, 'count':1, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(json_obj) + logger.log_struct({"severity":"INFO","jsonPayload":json_obj}) return create_api_response('Success',data=result) except Exception as e: job_status = "Failed" @@ -384,7 +384,7 @@ async def upload_large_file_into_chunks(file:UploadFile = File(...), chunkNumber graph = create_graph_database_connection(uri, userName, password, database) result = await asyncio.to_thread(upload_file, graph, model, file, chunkNumber, totalChunks, originalname, uri, CHUNK_DIR, MERGED_DIR) json_obj = {'api_name':'upload','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(json_obj) + logger.log_struct({"severity":"INFO","jsonPayload":json_obj}) if int(chunkNumber) == int(totalChunks): return create_api_response('Success',data=result, message='Source Node Created Successfully') else: @@ -406,7 +406,7 @@ async def get_structured_schema(uri=Form(), userName=Form(), password=Form(), da result = await asyncio.to_thread(get_labels_and_relationtypes, graph) logging.info(f'Schema result from DB: {result}') json_obj = {'api_name':'schema','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(json_obj) + logger.log_struct({"severity":"INFO","jsonPayload":json_obj}) return create_api_response('Success', data=result) except Exception as e: message="Unable to get the labels and relationtypes from neo4j database" @@ -475,7 +475,7 @@ async def delete_document_and_entities(uri=Form(), # entities_count = result[0]['deletedEntities'] if 'deletedEntities' in result[0] else 0 message = f"Deleted {files_list_size} documents with entities from database" json_obj = {'api_name':'delete_document_and_entities','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(json_obj) + logger.log_struct({"severity":"INFO","jsonPayload":json_obj}) return create_api_response('Success',message=message) except Exception as e: job_status = "Failed" From fd12e9ad4d4f222dc0ba0cdc576d5ac02a346629 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Thu, 12 Sep 2024 10:00:55 +0000 Subject: [PATCH 072/292] changed name --- backend/src/QA_integration.py | 4 ++-- backend/src/shared/constants.py | 2 +- frontend/src/utils/Constants.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/src/QA_integration.py b/backend/src/QA_integration.py index ecea7b50b..e6a25c225 100644 --- a/backend/src/QA_integration.py +++ b/backend/src/QA_integration.py @@ -190,7 +190,7 @@ def process_documents(docs, question, messages, llm, model,chat_mode_settings): "context": formatted_docs, "input": question }) - if chat_mode_settings["mode"] == "local_community_search": + if chat_mode_settings["mode"] == "entity search+vector": result = {'sources': list(), 'chunkdetails': list()} result.update(lc_entities) @@ -325,7 +325,7 @@ def get_neo4j_retriever(graph, document_names,chat_mode_settings, search_k=CHAT_ neo_db = initialize_neo4j_vector(graph, chat_mode_settings) document_names= list(map(str.strip, json.loads(document_names))) - search_k = LOCAL_COMMUNITY_TOP_K if chat_mode_settings["mode"] == "local_community_search" else CHAT_SEARCH_KWARG_K + search_k = LOCAL_COMMUNITY_TOP_K if chat_mode_settings["mode"] == "entity search+vector" else CHAT_SEARCH_KWARG_K retriever = create_retriever(neo_db, document_names,chat_mode_settings, search_k, score_threshold) return retriever except Exception as e: diff --git a/backend/src/shared/constants.py b/backend/src/shared/constants.py index a8661f8b7..acfaeea3d 100644 --- a/backend/src/shared/constants.py +++ b/backend/src/shared/constants.py @@ -312,7 +312,7 @@ "keyword_index": "keyword", "document_filter": False }, - "local_community_search": { + "entity search+vector": { "retrieval_query": LOCAL_COMMUNITY_SEARCH_QUERY.format(topChunks=LOCAL_COMMUNITY_TOP_CHUNKS, topCommunities=LOCAL_COMMUNITY_TOP_COMMUNITIES, topOutsideRels=LOCAL_COMMUNITY_TOP_OUTSIDE_RELS)+LOCAL_COMMUNITY_SEARCH_QUERY_SUFFIX, diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index b323f9d4c..a3f77c134 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -59,7 +59,7 @@ export const defaultLLM = llms?.includes('openai-gpt-4o') export const chatModes = process.env?.VITE_CHAT_MODES?.trim() != '' ? process.env.VITE_CHAT_MODES?.split(',') - : ['vector', 'graph', 'graph+vector', 'fulltext', 'graph+vector+fulltext', 'local community', 'global community']; + : ['vector', 'graph', 'graph+vector', 'fulltext', 'graph+vector+fulltext', 'entity search+vector', 'global community']; export const chunkSize = process.env.VITE_CHUNK_SIZE ? parseInt(process.env.VITE_CHUNK_SIZE) : 1 * 1024 * 1024; export const timeperpage = process.env.VITE_TIME_PER_PAGE ? parseInt(process.env.VITE_TIME_PER_PAGE) : 50; export const timePerByte = 0.2; From 21dd2837df121177f132f1f21d88d9c13c0f5a10 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Thu, 12 Sep 2024 10:12:01 +0000 Subject: [PATCH 073/292] modified the query --- backend/src/shared/constants.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/src/shared/constants.py b/backend/src/shared/constants.py index acfaeea3d..534061a85 100644 --- a/backend/src/shared/constants.py +++ b/backend/src/shared/constants.py @@ -273,14 +273,14 @@ LOCAL_COMMUNITY_SEARCH_QUERY_SUFFIX = """ -RETURN {{chunks: [c in chunks | c.text], +RETURN {chunks: [c in chunks | c.text], communities: [c in communities | c.summary], entities: [n in nodes | apoc.coll.removeAll(labels(n),["__Entity__"])[0] + ":"+ n.id + " " + coalesce(n.description, "")], relationships: [r in rels | startNode(r).id+" "+type(r)+" "+endNode(r).id], - outside: {{ + outside: { nodes: [n in outside[0].nodes | apoc.coll.removeAll(labels(n),["__Entity__"])[0] + ":"+n.id + " " + coalesce(n.description, "")], - relationships: [r in outside[0].rels | apoc.coll.removeAll(labels(startNode(r)),["__Entity__"])[0] + ":"+startNode(r).id+" "+type(r)+" "+apoc.coll.removeAll(labels(startNode(r)),["__Entity__"])[0] + ":"+endNode(r).id]}} - }} AS text, score, {{entities:metadata}} as metadata + relationships: [r in outside[0].rels | apoc.coll.removeAll(labels(startNode(r)),["__Entity__"])[0] + ":"+startNode(r).id+" "+type(r)+" "+apoc.coll.removeAll(labels(startNode(r)),["__Entity__"])[0] + ":"+endNode(r).id]} + } AS text, score, {entities:metadata} as metadata """ LOCAL_COMMUNITY_DETAILS_QUERY_PREFIX = """ From ccfabc7fbc5179e09d731907172079b7abf17a8f Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Thu, 12 Sep 2024 11:19:18 +0000 Subject: [PATCH 074/292] updated entities param --- backend/src/QA_integration.py | 6 +++--- backend/src/shared/constants.py | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/backend/src/QA_integration.py b/backend/src/QA_integration.py index e6a25c225..cd8fb5e5c 100644 --- a/backend/src/QA_integration.py +++ b/backend/src/QA_integration.py @@ -155,7 +155,7 @@ def format_documents(documents, model): formatted_docs = [] sources = set() - lc_entities = {} + lc_entities = {'entities':list()} for doc in sorted_documents: try: @@ -357,12 +357,12 @@ def process_chat_response(messages,history, question, model, graph, document_nam try: llm, doc_retriever, model_version = setup_chat(model, graph, document_names,chat_mode_settings) - docs = retrieve_documents(doc_retriever, messages) + docs = retrieve_documents(doc_retriever, messages) if docs: content, result, total_tokens = process_documents(docs, question, messages, llm, model,chat_mode_settings) else: content = "I couldn't find any relevant documents to answer your question." - result = {"sources": [], "chunkdetails": []} + result = {"sources": [], "chunkdetails": [],"entities":[]} total_tokens = 0 ai_response = AIMessage(content=content) diff --git a/backend/src/shared/constants.py b/backend/src/shared/constants.py index 534061a85..3ae5f7693 100644 --- a/backend/src/shared/constants.py +++ b/backend/src/shared/constants.py @@ -271,7 +271,6 @@ }} as outside """ - LOCAL_COMMUNITY_SEARCH_QUERY_SUFFIX = """ RETURN {chunks: [c in chunks | c.text], communities: [c in communities | c.summary], From dde29f2d79d27fda6dd530485d07be27d057e085 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Fri, 13 Sep 2024 05:23:23 +0000 Subject: [PATCH 075/292] added document to details --- backend/src/chunkid_entities.py | 4 ++-- backend/src/shared/constants.py | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/backend/src/chunkid_entities.py b/backend/src/chunkid_entities.py index e6ca8a512..82dd5ef44 100644 --- a/backend/src/chunkid_entities.py +++ b/backend/src/chunkid_entities.py @@ -88,12 +88,12 @@ def process_chunkids(driver, chunk_ids): logging.error(f"chunkid_entities module: Error processing chunk ids: {chunk_ids}. Error: {e}") raise -def remove_duplicate_nodes(nodes): +def remove_duplicate_nodes(nodes,property="element_id"): unique_nodes = [] seen_element_ids = set() for node in nodes: - element_id = node['element_id'] + element_id = node[property] if element_id not in seen_element_ids: unique_nodes.append(node) seen_element_ids.add(element_id) diff --git a/backend/src/shared/constants.py b/backend/src/shared/constants.py index 3ae5f7693..993d8d234 100644 --- a/backend/src/shared/constants.py +++ b/backend/src/shared/constants.py @@ -289,7 +289,10 @@ """ LOCAL_COMMUNITY_DETAILS_QUERY_SUFFIX = """ -RETURN [chunk in chunks | chunk {.*, embedding:null}] as chunks, +WITH * +UNWIND chunks as c +MATCH (c)-[:PART_OF]->(d:Document) +RETURN [c {.*, embedding:null, fileName:d.fileName, fileType:d.fileType}] as chunks, [community in communities | community {.*, embedding:null}] as communities, [node in nodes+outside[0].nodes | {element_id:elementId(node), labels:labels(node), properties:{id:node.id,description:node.description}}] as nodes, [r in rels+outside[0].rels | {startNode:{element_id:elementId(startNode(r)), labels:labels(startNode(r)), properties:{id:startNode(r).id,description:startNode(r).description}}, @@ -297,7 +300,6 @@ relationship: {type:type(r), element_id:elementId(r)}}] as entities """ - CHAT_MODE_CONFIG_MAP= { "vector": { "retrieval_query": VECTOR_SEARCH_QUERY, From 82be95b34841015ac7dde508e23f3cf465602b79 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Fri, 13 Sep 2024 05:39:18 +0000 Subject: [PATCH 076/292] format fixes --- frontend/src/components/Content.tsx | 4 ++-- frontend/src/components/FileTable.tsx | 4 ++-- frontend/src/components/QuickStarter.tsx | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 052e095b3..8bbe10f92 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -513,7 +513,7 @@ const Content: React.FC = ({ if (response.data.status === 'Failure') { throw new Error(response.data.error); } - const isStartFromBegining = retryoption === RETRY_OPIONS[0] || retryoption===RETRY_OPIONS[1]; + const isStartFromBegining = retryoption === RETRY_OPIONS[0] || retryoption === RETRY_OPIONS[1]; setFilesData((prev) => { return prev.map((f) => { return f.name === filename @@ -891,4 +891,4 @@ const Content: React.FC = ({ ); }; -export default Content; \ No newline at end of file +export default Content; diff --git a/frontend/src/components/FileTable.tsx b/frontend/src/components/FileTable.tsx index 04e2a8841..50e03a5cd 100644 --- a/frontend/src/components/FileTable.tsx +++ b/frontend/src/components/FileTable.tsx @@ -35,7 +35,7 @@ import { } from '../utils/Utils'; import { SourceNode, CustomFile, FileTableProps, UserCredentials, statusupdate, ChildRef } from '../types'; import { useCredentials } from '../context/UserCredentials'; -import { ArrowPathIconSolid, MagnifyingGlassCircleIconSolid } from '@neo4j-ndl/react/icons'; +import { MagnifyingGlassCircleIconSolid } from '@neo4j-ndl/react/icons'; import CustomProgressBar from './UI/CustomProgressBar'; import subscribe from '../services/PollingAPI'; import { triggerStatusUpdateAPI } from '../services/ServerSideStatusUpdateAPI'; @@ -49,7 +49,7 @@ import IndeterminateCheckbox from './UI/CustomCheckBox'; import { showErrorToast, showNormalToast } from '../utils/toasts'; let onlyfortheFirstRender = true; const FileTable = forwardRef((props, ref) => { - const { isExpanded, connectionStatus, setConnectionStatus, onInspect, onRetry } = props; + const { isExpanded, connectionStatus, setConnectionStatus, onInspect } = props; const { filesData, setFilesData, model, rowSelection, setRowSelection, setSelectedRows, setProcessedCount, queue } = useFileContext(); const { userCredentials } = useCredentials(); diff --git a/frontend/src/components/QuickStarter.tsx b/frontend/src/components/QuickStarter.tsx index 29832fee1..db2cba7e7 100644 --- a/frontend/src/components/QuickStarter.tsx +++ b/frontend/src/components/QuickStarter.tsx @@ -42,4 +42,4 @@ const QuickStarter: React.FunctionComponent = () => { ); }; -export default QuickStarter; \ No newline at end of file +export default QuickStarter; From 93a4698e253661bb95d1a0ad472eba077f5d3e84 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Fri, 13 Sep 2024 07:06:33 +0000 Subject: [PATCH 077/292] added global embedding --- backend/score.py | 2 +- backend/src/make_relationships.py | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/backend/score.py b/backend/score.py index 54cbb3ef3..99e8bd812 100644 --- a/backend/score.py +++ b/backend/score.py @@ -446,7 +446,7 @@ async def generate(): graph = create_graph_database_connection(uri, userName, decoded_password, database) graphDb_data_Access = graphDBdataAccess(graph) result = graphDb_data_Access.get_current_status_document_node(file_name) - print(f'Result of document status in SSE : {result}') + # print(f'Result of document status in SSE : {result}') if len(result) > 0: status = json.dumps({'fileName':file_name, 'status':result[0]['Status'], diff --git a/backend/src/make_relationships.py b/backend/src/make_relationships.py index 4783c5abe..1ea2729e5 100644 --- a/backend/src/make_relationships.py +++ b/backend/src/make_relationships.py @@ -9,6 +9,9 @@ logging.basicConfig(format='%(asctime)s - %(message)s',level='INFO') +EMBEDDING_MODEL = os.getenv('EMBEDDING_MODEL') +EMBEDDING_FUNCTION , EMBEDDING_DIMENSION = load_embedding_model(EMBEDDING_MODEL) + def merge_relationship_between_chunk_and_entites(graph: Neo4jGraph, graph_documents_chunk_chunk_Id : list): batch_data = [] logging.info("Create HAS_ENTITY relationship between chunks and entities") @@ -39,9 +42,9 @@ def merge_relationship_between_chunk_and_entites(graph: Neo4jGraph, graph_docume def update_embedding_create_vector_index(graph, chunkId_chunkDoc_list, file_name): #create embedding isEmbedding = os.getenv('IS_EMBEDDING') - embedding_model = os.getenv('EMBEDDING_MODEL') + # embedding_model = os.getenv('EMBEDDING_MODEL') - embeddings, dimension = load_embedding_model(embedding_model) + embeddings, dimension = EMBEDDING_FUNCTION , EMBEDDING_DIMENSION logging.info(f'embedding model:{embeddings} and dimesion:{dimension}') data_for_query = [] logging.info(f"update embedding and vector index for chunks") From 7e0f1c80c1d73afae8d02a1039b309d4a53dd7e6 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Fri, 13 Sep 2024 09:09:13 +0000 Subject: [PATCH 078/292] added database --- backend/score.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backend/score.py b/backend/score.py index 99e8bd812..a9c3f1f4e 100644 --- a/backend/score.py +++ b/backend/score.py @@ -325,6 +325,7 @@ async def chunk_entities(uri=Form(),userName=Form(), password=Form(), database=F @app.post("/graph_query") async def graph_query( uri: str = Form(), + database: str = Form(), userName: str = Form(), password: str = Form(), document_names: str = Form(None), @@ -336,6 +337,7 @@ async def graph_query( uri=uri, username=userName, password=password, + database=database, document_names=document_names ) json_obj = {'api_name':'graph_query','db_url':uri,'document_names':document_names, 'logging_time': formatted_time(datetime.now(timezone.utc))} From d1eda2be34445d3dcaa4a0cdee0fa217abd7157b Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Fri, 13 Sep 2024 09:15:47 +0000 Subject: [PATCH 079/292] added database --- backend/src/graph_query.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/graph_query.py b/backend/src/graph_query.py index bf51cb76c..77f6e9d0a 100644 --- a/backend/src/graph_query.py +++ b/backend/src/graph_query.py @@ -181,7 +181,7 @@ def get_completed_documents(driver): return documents -def get_graph_results(uri, username, password,document_names): +def get_graph_results(uri, username, password,database,document_names): """ Retrieves graph data by executing a specified Cypher query using credentials and parameters provided. Processes the results to extract nodes and relationships and packages them in a structured output. @@ -198,7 +198,7 @@ def get_graph_results(uri, username, password,document_names): """ try: logging.info(f"Starting graph query process") - driver = get_graphDB_driver(uri, username, password) + driver = get_graphDB_driver(uri, username, password,database) document_names= list(map(str.strip, json.loads(document_names))) query = GRAPH_QUERY.format(graph_chunk_limit=GRAPH_CHUNK_LIMIT) records, summary , keys = execute_query(driver, query.strip(), document_names) From 3c0a5df61871df5193195ab7ecab703730326e6c Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Fri, 13 Sep 2024 10:16:01 +0000 Subject: [PATCH 080/292] modified is_entity --- backend/score.py | 2 +- backend/src/chunkid_entities.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/score.py b/backend/score.py index f4653ef63..7963146c3 100644 --- a/backend/score.py +++ b/backend/score.py @@ -309,7 +309,7 @@ async def chat_bot(uri=Form(),model=Form(None),userName=Form(), password=Form(), async def chunk_entities(uri=Form(),userName=Form(), password=Form(), database=Form(), chunk_ids=Form(None),is_entity=Form()): try: logging.info(f"URI: {uri}, Username: {userName}, chunk_ids: {chunk_ids}") - result = await asyncio.to_thread(get_entities_from_chunkids,uri=uri, username=userName, password=password, database=database,chunk_ids=chunk_ids,is_entity=is_entity) + result = await asyncio.to_thread(get_entities_from_chunkids,uri=uri, username=userName, password=password, database=database,chunk_ids=chunk_ids,is_entity=json.loads(is_entity.lower())) json_obj = {'api_name':'chunk_entities','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} logger.log_struct({"severity":"INFO","jsonPayload":json_obj}) return create_api_response('Success',data=result) diff --git a/backend/src/chunkid_entities.py b/backend/src/chunkid_entities.py index 82dd5ef44..eee2c0d45 100644 --- a/backend/src/chunkid_entities.py +++ b/backend/src/chunkid_entities.py @@ -146,6 +146,7 @@ def get_entities_from_chunkids(uri, username, password, database ,chunk_ids,is_e driver = get_graphDB_driver(uri, username, password,database) if not is_entity: if chunk_ids: + logging.info(f"chunkid_entities module: Starting for chunk ids : {chunk_ids}") result = process_chunkids(driver,chunk_ids) else: logging.info(f"chunkid_entities module: No chunk ids are passed") @@ -157,6 +158,7 @@ def get_entities_from_chunkids(uri, username, password, database ,chunk_ids,is_e return result if chunk_ids: result = process_entityids(driver,chunk_ids) + logging.info(f"chunkid_entities module: Starting for entity ids : {chunk_ids}") else: logging.info(f"chunkid_entities module: No entity ids are passed") result = { From 9e349192edddc0a9184f25906c9ee4461283f9d4 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Mon, 16 Sep 2024 05:48:51 +0000 Subject: [PATCH 081/292] modifies chunk entities --- backend/src/chunkid_entities.py | 11 ++++++----- backend/src/shared/constants.py | 5 ++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/backend/src/chunkid_entities.py b/backend/src/chunkid_entities.py index eee2c0d45..89ea069f6 100644 --- a/backend/src/chunkid_entities.py +++ b/backend/src/chunkid_entities.py @@ -117,11 +117,12 @@ def process_entityids(driver, chunk_ids): records, summary, keys = driver.execute_query(query, entityIds=entity_ids_list) result = process_records(records) - result["nodes"].extend(records[0]["nodes"]) - result["nodes"] = remove_duplicate_nodes(result["nodes"]) - logging.info(f"Nodes and relationships are processed") - result["chunk_data"] = records[0]["chunks"] - result["community_data"] = records[0]["communities"] + if records: + result["nodes"].extend(records[0]["nodes"]) + result["nodes"] = remove_duplicate_nodes(result["nodes"]) + logging.info(f"Nodes and relationships are processed") + result["chunk_data"] = records[0]["chunks"] + result["community_data"] = records[0]["communities"] logging.info(f"Query process completed successfully for chunk ids: {chunk_ids}") return result except Exception as e: diff --git a/backend/src/shared/constants.py b/backend/src/shared/constants.py index 993d8d234..4ec88e8a5 100644 --- a/backend/src/shared/constants.py +++ b/backend/src/shared/constants.py @@ -248,7 +248,7 @@ collect {{ UNWIND nodes as n MATCH (n)-[:IN_COMMUNITY]->(c:__Community__) - WITH c, c.rank as rank, c.weight AS weight + WITH c, c.community_rank as rank, c.weight AS weight RETURN c ORDER BY rank, weight DESC LIMIT {topCommunities} @@ -287,12 +287,11 @@ MATCH (node) WHERE elementId(node) = id WITH node, 1.0 as score """ - LOCAL_COMMUNITY_DETAILS_QUERY_SUFFIX = """ WITH * UNWIND chunks as c MATCH (c)-[:PART_OF]->(d:Document) -RETURN [c {.*, embedding:null, fileName:d.fileName, fileType:d.fileType}] as chunks, +RETURN [c {.*, embedding:null, fileName:d.fileName, fileSource:d.fileSource}] as chunks, [community in communities | community {.*, embedding:null}] as communities, [node in nodes+outside[0].nodes | {element_id:elementId(node), labels:labels(node), properties:{id:node.id,description:node.description}}] as nodes, [r in rels+outside[0].rels | {startNode:{element_id:elementId(startNode(r)), labels:labels(startNode(r)), properties:{id:startNode(r).id,description:startNode(r).description}}, From fa1ca363979bfb8762a5a5150f76680aaa1ef8b2 Mon Sep 17 00:00:00 2001 From: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Date: Mon, 16 Sep 2024 06:30:20 +0000 Subject: [PATCH 082/292] Added secweb to fix security issues --- backend/requirements.txt | 1 + backend/score.py | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/backend/requirements.txt b/backend/requirements.txt index 46c57aea5..7c67f13fa 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -179,3 +179,4 @@ sentence-transformers==3.0.1 google-cloud-logging==3.10.0 PyMuPDF==1.24.5 pypandoc==1.13 +Secweb==1.11.0 \ No newline at end of file diff --git a/backend/score.py b/backend/score.py index ca3707ce1..8f62b29f1 100644 --- a/backend/score.py +++ b/backend/score.py @@ -26,6 +26,11 @@ from datetime import datetime, timezone import time import gc +from Secweb import SecWeb +from Secweb.StrictTransportSecurity import HSTS +from Secweb.ContentSecurityPolicy import ContentSecurityPolicy +from Secweb.XContentTypeOptions import XContentTypeOptions +from Secweb.XFrameOptions import XFrame logger = CustomLogger() CHUNK_DIR = os.path.join(os.path.dirname(__file__), "chunks") @@ -42,6 +47,11 @@ def sick(): return False app = FastAPI() +SecWeb(app=app, Option={'referrer': False, 'xframe': False}) +app.add_middleware(HSTS, Option={'max-age': 4, 'preload': True}) +app.add_middleware(ContentSecurityPolicy, Option={'default-src': ["'self'"], 'base-uri': ["'self'"], 'block-all-mixed-content': []}, script_nonce=False, style_nonce=False, report_only=False) +app.add_middleware(XContentTypeOptions) +app.add_middleware(XFrame, Option={'X-Frame-Options': 'DENY'}) app.add_middleware( CORSMiddleware, From 62f454dedba7d56f3acb36080b1d90406449a65a Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Mon, 16 Sep 2024 09:03:20 +0000 Subject: [PATCH 083/292] removed QA integration --- backend/src/QA_integration_new.py | 424 ------------------------------ 1 file changed, 424 deletions(-) delete mode 100644 backend/src/QA_integration_new.py diff --git a/backend/src/QA_integration_new.py b/backend/src/QA_integration_new.py deleted file mode 100644 index eeac78c1e..000000000 --- a/backend/src/QA_integration_new.py +++ /dev/null @@ -1,424 +0,0 @@ -from langchain_community.vectorstores.neo4j_vector import Neo4jVector -from langchain.graphs import Neo4jGraph -import os -from dotenv import load_dotenv -import logging -from langchain_community.chat_message_histories import Neo4jChatMessageHistory -from src.llm import get_llm -from src.shared.common_fn import load_embedding_model -import re -from typing import Any -from datetime import datetime -import time -from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder -from langchain_core.output_parsers import StrOutputParser -from langchain_core.runnables import RunnableBranch -from langchain.retrievers import ContextualCompressionRetriever -from langchain_community.document_transformers import EmbeddingsRedundantFilter -from langchain.retrievers.document_compressors import EmbeddingsFilter -from langchain.retrievers.document_compressors import DocumentCompressorPipeline -from langchain_text_splitters import TokenTextSplitter -from langchain_core.messages import HumanMessage,AIMessage -from src.shared.constants import * -from src.llm import get_llm -from langchain.chains import GraphCypherQAChain -import json - -## Chat models -from langchain_openai import ChatOpenAI, AzureChatOpenAI -from langchain_google_vertexai import ChatVertexAI -from langchain_groq import ChatGroq -from langchain_anthropic import ChatAnthropic -from langchain_fireworks import ChatFireworks -from langchain_aws import ChatBedrock -from langchain_community.chat_models import ChatOllama - -load_dotenv() - -EMBEDDING_MODEL = os.getenv('EMBEDDING_MODEL') -EMBEDDING_FUNCTION , _ = load_embedding_model(EMBEDDING_MODEL) - - -def get_neo4j_retriever(graph, retrieval_query,document_names,mode,index_name="vector",keyword_index="keyword", search_k=CHAT_SEARCH_KWARG_K, score_threshold=CHAT_SEARCH_KWARG_SCORE_THRESHOLD): - try: - if mode == "fulltext" or mode == "graph + vector + fulltext": - neo_db = Neo4jVector.from_existing_graph( - embedding=EMBEDDING_FUNCTION, - index_name=index_name, - retrieval_query=retrieval_query, - graph=graph, - search_type="hybrid", - node_label="Chunk", - embedding_node_property="embedding", - text_node_properties=["text"], - keyword_index_name=keyword_index - ) - # neo_db = Neo4jVector.from_existing_index( - # embedding=EMBEDDING_FUNCTION, - # index_name=index_name, - # retrieval_query=retrieval_query, - # graph=graph, - # search_type="hybrid", - # keyword_index_name=keyword_index - # ) - logging.info(f"Successfully retrieved Neo4jVector index '{index_name}' and keyword index '{keyword_index}'") - else: - neo_db = Neo4jVector.from_existing_index( - embedding=EMBEDDING_FUNCTION, - index_name=index_name, - retrieval_query=retrieval_query, - graph=graph - ) - logging.info(f"Successfully retrieved Neo4jVector index '{index_name}'") - document_names= list(map(str.strip, json.loads(document_names))) - if document_names: - retriever = neo_db.as_retriever(search_type="similarity_score_threshold",search_kwargs={'k': search_k, "score_threshold": score_threshold,'filter':{'fileName': {'$in': document_names}}}) - logging.info(f"Successfully created retriever for index '{index_name}' with search_k={search_k}, score_threshold={score_threshold} for documents {document_names}") - else: - retriever = neo_db.as_retriever(search_type="similarity_score_threshold",search_kwargs={'k': search_k, "score_threshold": score_threshold}) - logging.info(f"Successfully created retriever for index '{index_name}' with search_k={search_k}, score_threshold={score_threshold}") - return retriever - except Exception as e: - logging.error(f"Error retrieving Neo4jVector index '{index_name}' or creating retriever: {e}") - raise Exception("An error occurred while retrieving the Neo4jVector index '{index_name}' or creating the retriever. Please drop and create a new vector index: {e}") from e - -def create_document_retriever_chain(llm, retriever): - try: - logging.info("Starting to create document retriever chain") - - query_transform_prompt = ChatPromptTemplate.from_messages( - [ - ("system", QUESTION_TRANSFORM_TEMPLATE), - MessagesPlaceholder(variable_name="messages") - ] - ) - - output_parser = StrOutputParser() - - splitter = TokenTextSplitter(chunk_size=CHAT_DOC_SPLIT_SIZE, chunk_overlap=0) - embeddings_filter = EmbeddingsFilter( - embeddings=EMBEDDING_FUNCTION, - similarity_threshold=CHAT_EMBEDDING_FILTER_SCORE_THRESHOLD - ) - - pipeline_compressor = DocumentCompressorPipeline( - transformers=[splitter, embeddings_filter] - ) - - compression_retriever = ContextualCompressionRetriever( - base_compressor=pipeline_compressor, base_retriever=retriever - ) - - query_transforming_retriever_chain = RunnableBranch( - ( - lambda x: len(x.get("messages", [])) == 1, - (lambda x: x["messages"][-1].content) | compression_retriever, - ), - query_transform_prompt | llm | output_parser | compression_retriever, - ).with_config(run_name="chat_retriever_chain") - - logging.info("Successfully created document retriever chain") - return query_transforming_retriever_chain - - except Exception as e: - logging.error(f"Error creating document retriever chain: {e}", exc_info=True) - raise - - -def create_neo4j_chat_message_history(graph, session_id): - """ - Creates and returns a Neo4jChatMessageHistory instance. - - """ - try: - - history = Neo4jChatMessageHistory( - graph=graph, - session_id=session_id - ) - return history - - except Exception as e: - logging.error(f"Error creating Neo4jChatMessageHistory: {e}") - raise - -def format_documents(documents,model): - prompt_token_cutoff = 4 - for models,value in CHAT_TOKEN_CUT_OFF.items(): - if model in models: - prompt_token_cutoff = value - - sorted_documents = sorted(documents, key=lambda doc: doc.state["query_similarity_score"], reverse=True) - sorted_documents = sorted_documents[:prompt_token_cutoff] - - formatted_docs = [] - sources = set() - - for doc in sorted_documents: - source = doc.metadata['source'] - sources.add(source) - - formatted_doc = ( - "Document start\n" - f"This Document belongs to the source {source}\n" - f"Content: {doc.page_content}\n" - "Document end\n" - ) - formatted_docs.append(formatted_doc) - - return "\n\n".join(formatted_docs), sources - -def get_rag_chain(llm,system_template=CHAT_SYSTEM_TEMPLATE): - question_answering_prompt = ChatPromptTemplate.from_messages( - [ - ("system", system_template), - MessagesPlaceholder(variable_name="messages"), - ( - "human", - "User question: {input}" - ), - ] - ) - question_answering_chain = question_answering_prompt | llm - - return question_answering_chain - -def get_sources_and_chunks(sources_used, docs): - chunkdetails_list = [] - sources_used_set = set(sources_used) - - for doc in docs: - source = doc.metadata["source"] - chunkdetails = doc.metadata["chunkdetails"] - if source in sources_used_set: - chunkdetails = [{**chunkdetail, "score": round(chunkdetail["score"], 4)} for chunkdetail in chunkdetails] - chunkdetails_list.extend(chunkdetails) - - result = { - 'sources': sources_used, - 'chunkdetails': chunkdetails_list - } - return result - -def summarize_messages(llm,history,stored_messages): - if len(stored_messages) == 0: - return False - summarization_prompt = ChatPromptTemplate.from_messages( - [ - MessagesPlaceholder(variable_name="chat_history"), - ( - "human", - "Summarize the above chat messages into a concise message, focusing on key points and relevant details that could be useful for future conversations. Exclude all introductions and extraneous information." - ), - ] - ) - - summarization_chain = summarization_prompt | llm - - summary_message = summarization_chain.invoke({"chat_history": stored_messages}) - - history.clear() - history.add_user_message("Our current convertaion summary till now") - history.add_message(summary_message) - return True - - -def get_total_tokens(ai_response,llm): - - if isinstance(llm,(ChatOpenAI,AzureChatOpenAI,ChatFireworks,ChatGroq)): - total_tokens = ai_response.response_metadata['token_usage']['total_tokens'] - elif isinstance(llm,(ChatVertexAI)): - total_tokens = ai_response.response_metadata['usage_metadata']['prompt_token_count'] - elif isinstance(llm,(ChatBedrock)): - total_tokens = ai_response.response_metadata['usage']['total_tokens'] - elif isinstance(llm,(ChatAnthropic)): - input_tokens = int(ai_response.response_metadata['usage']['input_tokens']) - output_tokens = int(ai_response.response_metadata['usage']['output_tokens']) - total_tokens = input_tokens + output_tokens - elif isinstance(llm,(ChatOllama)): - total_tokens = ai_response.response_metadata["prompt_eval_count"] - else: - total_tokens = 0 - return total_tokens - - -def clear_chat_history(graph,session_id): - history = Neo4jChatMessageHistory( - graph=graph, - session_id=session_id - ) - history.clear() - return { - "session_id": session_id, - "message": "The chat History is cleared", - "user": "chatbot" - } - -def setup_chat(model, graph, document_names,retrieval_query,mode): - start_time = time.time() - if model in ["diffbot"]: - model = "openai-gpt-4o" - llm,model_name = get_llm(model) - logging.info(f"Model called in chat {model} and model version is {model_name}") - retriever = get_neo4j_retriever(graph=graph,retrieval_query=retrieval_query,document_names=document_names,mode=mode) - doc_retriever = create_document_retriever_chain(llm, retriever) - chat_setup_time = time.time() - start_time - logging.info(f"Chat setup completed in {chat_setup_time:.2f} seconds") - - return llm, doc_retriever, model_name - -def retrieve_documents(doc_retriever, messages): - start_time = time.time() - docs = doc_retriever.invoke({"messages": messages}) - doc_retrieval_time = time.time() - start_time - logging.info(f"Documents retrieved in {doc_retrieval_time:.2f} seconds") - return docs - -def process_documents(docs, question, messages, llm,model): - start_time = time.time() - formatted_docs, sources = format_documents(docs,model) - rag_chain = get_rag_chain(llm=llm) - ai_response = rag_chain.invoke({ - "messages": messages[:-1], - "context": formatted_docs, - "input": question - }) - result = get_sources_and_chunks(sources, docs) - content = ai_response.content - total_tokens = get_total_tokens(ai_response,llm) - - - predict_time = time.time() - start_time - logging.info(f"Final Response predicted in {predict_time:.2f} seconds") - - return content, result, total_tokens - -def summarize_and_log(history, messages, llm): - start_time = time.time() - summarize_messages(llm, history, messages) - history_summarized_time = time.time() - start_time - logging.info(f"Chat History summarized in {history_summarized_time:.2f} seconds") - - -def create_graph_chain(model, graph): - try: - logging.info(f"Graph QA Chain using LLM model: {model}") - - cypher_llm,model_name = get_llm(model) - qa_llm,model_name = get_llm(model) - graph_chain = GraphCypherQAChain.from_llm( - cypher_llm=cypher_llm, - qa_llm=qa_llm, - validate_cypher= True, - graph=graph, - # verbose=True, - return_intermediate_steps = True, - top_k=3 - ) - - logging.info("GraphCypherQAChain instance created successfully.") - return graph_chain,qa_llm,model_name - - except Exception as e: - logging.error(f"An error occurred while creating the GraphCypherQAChain instance. : {e}") - - -def get_graph_response(graph_chain, question): - try: - cypher_res = graph_chain.invoke({"query": question}) - - response = cypher_res.get("result") - cypher_query = "" - context = [] - - for step in cypher_res.get("intermediate_steps", []): - if "query" in step: - cypher_string = step["query"] - cypher_query = cypher_string.replace("cypher\n", "").replace("\n", " ").strip() - elif "context" in step: - context = step["context"] - return { - "response": response, - "cypher_query": cypher_query, - "context": context - } - - except Exception as e: - logging.error("An error occurred while getting the graph response : {e}") - -def QA_RAG(graph, model, question, document_names,session_id, mode): - try: - logging.info(f"Chat Mode : {mode}") - history = create_neo4j_chat_message_history(graph, session_id) - messages = history.messages - user_question = HumanMessage(content=question) - messages.append(user_question) - - if mode == "graph": - graph_chain, qa_llm,model_version = create_graph_chain(model,graph) - graph_response = get_graph_response(graph_chain,question) - ai_response = AIMessage(content=graph_response["response"]) if graph_response["response"] else AIMessage(content="Something went wrong") - messages.append(ai_response) - summarize_and_log(history, messages, qa_llm) - - result = { - "session_id": session_id, - "message": graph_response["response"], - "info": { - "model": model_version, - 'cypher_query':graph_response["cypher_query"], - "context" : graph_response["context"], - "mode" : mode, - "response_time": 0 - }, - "user": "chatbot" - } - return result - elif mode == "vector" or mode == "fulltext": - retrieval_query = VECTOR_SEARCH_QUERY - else: - retrieval_query = VECTOR_GRAPH_SEARCH_QUERY.format(no_of_entites=VECTOR_GRAPH_SEARCH_ENTITY_LIMIT) - - llm, doc_retriever, model_version = setup_chat(model, graph, document_names,retrieval_query,mode) - - docs = retrieve_documents(doc_retriever, messages) - - if docs: - content, result, total_tokens = process_documents(docs, question, messages, llm,model) - else: - content = "I couldn't find any relevant documents to answer your question." - result = {"sources": [], "chunkdetails": []} - total_tokens = 0 - - ai_response = AIMessage(content=content) - messages.append(ai_response) - summarize_and_log(history, messages, llm) - - return { - "session_id": session_id, - "message": content, - "info": { - "sources": result["sources"], - "model": model_version, - "chunkdetails": result["chunkdetails"], - "total_tokens": total_tokens, - "response_time": 0, - "mode": mode - }, - "user": "chatbot" - } - - except Exception as e: - logging.exception(f"Exception in QA component at {datetime.now()}: {str(e)}") - error_name = type(e).__name__ - return { - "session_id": session_id, - "message": "Something went wrong", - "info": { - "sources": [], - "chunkids": [], - "error": f"{error_name} :- {str(e)}", - "mode": mode - }, - "user": "chatbot" - } From 4c7821e17d238113fd124e0a8c83b13a9a209fd5 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Mon, 16 Sep 2024 09:20:06 +0000 Subject: [PATCH 084/292] created neo4j from existing index --- backend/src/QA_integration.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/backend/src/QA_integration.py b/backend/src/QA_integration.py index cd8fb5e5c..d28459a9b 100644 --- a/backend/src/QA_integration.py +++ b/backend/src/QA_integration.py @@ -288,16 +288,26 @@ def initialize_neo4j_vector(graph, chat_mode_settings): ) logging.info(f"Successfully retrieved Neo4jVector Fulltext index '{index_name}' and keyword index '{keyword_index}'") else: - neo_db = Neo4jVector.from_existing_index( + # neo_db = Neo4jVector.from_existing_index( + # embedding=EMBEDDING_FUNCTION, + # index_name=index_name, + # retrieval_query=retrieval_query, + # graph=graph + # ) + neo_db = Neo4jVector.from_existing_graph( embedding=EMBEDDING_FUNCTION, index_name=index_name, retrieval_query=retrieval_query, - graph=graph + graph=graph, + node_label="Chunk", + embedding_node_property="embedding", + text_node_properties=["text"] ) logging.info(f"Successfully retrieved Neo4jVector index '{index_name}'") except Exception as e: - logging.error(f"Error retrieving Neo4jVector index : {e}") + index_name = chat_mode_settings.get("index_name") + logging.error(f"Error retrieving Neo4jVector index {index_name} : {e}") raise return neo_db @@ -329,8 +339,9 @@ def get_neo4j_retriever(graph, document_names,chat_mode_settings, search_k=CHAT_ retriever = create_retriever(neo_db, document_names,chat_mode_settings, search_k, score_threshold) return retriever except Exception as e: - logging.error(f"Error retrieving Neo4jVector index or creating retriever: {e}") - raise Exception("An error occurred while retrieving the Neo4jVector index or creating the retriever. Please drop and create a new vector index: {e}") from e + index_name = chat_mode_settings.get("index_name") + logging.error(f"Error retrieving Neo4jVector index {index_name} or creating retriever: {e}") + raise Exception(f"An error occurred while retrieving the Neo4jVector index or creating the retriever. Please drop and create a new vector index '{index_name}': {e}") from e def setup_chat(model, graph, document_names, chat_mode_settings): From 4206ec00ad5f111a6a26efa3e1aaea0e5fc216db Mon Sep 17 00:00:00 2001 From: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Date: Mon, 16 Sep 2024 10:40:20 +0000 Subject: [PATCH 085/292] modified script --- backend/test_integrationqa.py | 356 +++++++++++++++++----------------- 1 file changed, 178 insertions(+), 178 deletions(-) diff --git a/backend/test_integrationqa.py b/backend/test_integrationqa.py index b5a50de60..7b2b110d4 100644 --- a/backend/test_integrationqa.py +++ b/backend/test_integrationqa.py @@ -5,7 +5,6 @@ import pandas as pd from datetime import datetime as dt from dotenv import load_dotenv - from score import * from src.main import * from src.QA_integration_new import QA_RAG @@ -26,163 +25,163 @@ graph = create_graph_database_connection(URI, USERNAME, PASSWORD, DATABASE) def create_source_node_local(graph, model, file_name): - """Creates a source node for a local file.""" - source_node = sourceNode() - source_node.file_name = file_name - source_node.file_type = 'pdf' - source_node.file_size = '1087' - source_node.file_source = 'local file' - source_node.model = model - source_node.created_at = dt.now() - graphDB_data_Access = graphDBdataAccess(graph) - graphDB_data_Access.create_source_node(source_node) - return source_node + """Creates a source node for a local file.""" + source_node = sourceNode() + source_node.file_name = file_name + source_node.file_type = 'pdf' + source_node.file_size = '1087' + source_node.file_source = 'local file' + source_node.model = model + source_node.created_at = dt.now() + graphDB_data_Access = graphDBdataAccess(graph) + graphDB_data_Access.create_source_node(source_node) + return source_node def test_graph_from_file_local(model_name): - """Test graph creation from a local file.""" - file_name = 'About Amazon.pdf' - shutil.copyfile('/workspaces/llm-graph-builder/backend/files/About Amazon.pdf', - os.path.join(MERGED_DIR, file_name)) - - create_source_node_local(graph, model_name, file_name) - merged_file_path = os.path.join(MERGED_DIR, file_name) - - local_file_result = extract_graph_from_file_local_file( - URI, USERNAME, PASSWORD, DATABASE, model_name, merged_file_path, file_name, '', '' - ) - logging.info("Local file processing complete") - print(local_file_result) - - try: - assert local_file_result['status'] == 'Completed' - assert local_file_result['nodeCount'] > 0 - assert local_file_result['relationshipCount'] > 0 - print("Success") - except AssertionError as e: - print("Fail: ", e) - - return local_file_result + """Test graph creation from a local file.""" + file_name = 'About Amazon.pdf' + shutil.copyfile('/workspaces/llm-graph-builder/backend/files/About Amazon.pdf', + os.path.join(MERGED_DIR, file_name)) + + create_source_node_local(graph, model_name, file_name) + merged_file_path = os.path.join(MERGED_DIR, file_name) + + local_file_result = extract_graph_from_file_local_file( + URI, USERNAME, PASSWORD, DATABASE, model_name, merged_file_path, file_name, '', '',None + ) + logging.info("Local file processing complete") + print(local_file_result) + + try: + assert local_file_result['status'] == 'Completed' + assert local_file_result['nodeCount'] > 0 + assert local_file_result['relationshipCount'] > 0 + print("Success") + except AssertionError as e: + print("Fail: ", e) + + return local_file_result def test_graph_from_wikipedia(model_name): - """Test graph creation from a Wikipedia page.""" - wiki_query = 'https://en.wikipedia.org/wiki/Google_DeepMind' - source_type = 'Wikipedia' - file_name = "Google_DeepMind" - create_source_node_graph_url_wikipedia(graph, model_name, wiki_query, source_type) - - wiki_result = extract_graph_from_file_Wikipedia(URI, USERNAME, PASSWORD, DATABASE, model_name, file_name, 1, 'en', '', '') - logging.info("Wikipedia test done") - print(wiki_result) - - try: - assert wiki_result['status'] == 'Completed' - assert wiki_result['nodeCount'] > 0 - assert wiki_result['relationshipCount'] > 0 - print("Success") - except AssertionError as e: - print("Fail: ", e) - - return wiki_result + # try: + """Test graph creation from a Wikipedia page.""" + wiki_query = 'https://en.wikipedia.org/wiki/Ram_Mandir' + source_type = 'Wikipedia' + file_name = "Ram_Mandir" + create_source_node_graph_url_wikipedia(graph, model_name, wiki_query, source_type) + + wiki_result = extract_graph_from_file_Wikipedia(URI, USERNAME, PASSWORD, DATABASE, model_name, file_name, 'en',file_name, '', '',None) + logging.info("Wikipedia test done") + print(wiki_result) + try: + assert wiki_result['status'] == 'Completed' + assert wiki_result['nodeCount'] > 0 + assert wiki_result['relationshipCount'] > 0 + print("Success") + except AssertionError as e: + print("Fail: ", e) + + return wiki_result + # except Exception as ex: + # print(ex) def test_graph_website(model_name): - """Test graph creation from a Website page.""" - #graph, model, source_url, source_type - source_url = 'https://www.amazon.com/' - source_type = 'web-url' - create_source_node_graph_web_url(graph, model_name, source_url, source_type) - - weburl_result = extract_graph_from_web_page(URI, USERNAME, PASSWORD, DATABASE, model_name, source_url, '', '') - logging.info("WebUrl test done") - print(weburl_result) - - try: - assert weburl_result['status'] == 'Completed' - assert weburl_result['nodeCount'] > 0 - assert weburl_result['relationshipCount'] > 0 - print("Success") - except AssertionError as e: - print("Fail: ", e) - return weburl_result - + """Test graph creation from a Website page.""" + #graph, model, source_url, source_type + source_url = 'https://www.amazon.com/' + source_type = 'web-url' + file_name = [] + create_source_node_graph_web_url(graph, model_name, source_url, source_type) + + weburl_result = extract_graph_from_web_page(URI, USERNAME, PASSWORD, DATABASE, model_name, source_url,file_name, '', '',None) + logging.info("WebUrl test done") + print(weburl_result) + + try: + assert weburl_result['status'] == 'Completed' + assert weburl_result['nodeCount'] > 0 + assert weburl_result['relationshipCount'] > 0 + print("Success") + except AssertionError as e: + print("Fail: ", e) + return weburl_result def test_graph_from_youtube_video(model_name): - """Test graph creation from a YouTube video.""" - source_url = 'https://www.youtube.com/watch?v=T-qy-zPWgqA' - source_type = 'youtube' - - create_source_node_graph_url_youtube(graph, model_name, source_url, source_type) - youtube_result = extract_graph_from_file_youtube( - URI, USERNAME, PASSWORD, DATABASE, model_name, source_url, '', '' - ) - logging.info("YouTube Video test done") - print(youtube_result) - - try: - assert youtube_result['status'] == 'Completed' - assert youtube_result['nodeCount'] > 1 - assert youtube_result['relationshipCount'] > 1 - print("Success") - except AssertionError as e: - print("Failed: ", e) - - return youtube_result + """Test graph creation from a YouTube video.""" + source_url = 'https://www.youtube.com/watch?v=T-qy-zPWgqA' + source_type = 'youtube' + create_source_node_graph_url_youtube(graph, model_name, source_url, source_type) + youtube_result = extract_graph_from_file_youtube( + URI, USERNAME, PASSWORD, DATABASE, model_name, source_url, '', '' + ) + logging.info("YouTube Video test done") + print(youtube_result) + + try: + assert youtube_result['status'] == 'Completed' + assert youtube_result['nodeCount'] > 1 + assert youtube_result['relationshipCount'] > 1 + print("Success") + except AssertionError as e: + print("Failed: ", e) + + return youtube_result def test_chatbot_qna(model_name, mode='vector'): - """Test chatbot QnA functionality for different modes.""" - QA_n_RAG = QA_RAG(graph, model_name, 'Tell me about amazon', '[]', 1, mode) - print(QA_n_RAG) - print(len(QA_n_RAG['message'])) - - try: - assert len(QA_n_RAG['message']) > 20 - return QA_n_RAG - print("Success") - except AssertionError as e: - print("Failed ", e) - return QA_n_RAG - + """Test chatbot QnA functionality for different modes.""" + QA_n_RAG = QA_RAG(graph, model_name, 'Tell me about amazon', '[]', 1, mode) + print(QA_n_RAG) + print(len(QA_n_RAG['message'])) + + + try: + assert len(QA_n_RAG['message']) > 20 + return QA_n_RAG + print("Success") + except AssertionError as e: + print("Failed ", e) + return QA_n_RAG + #Get Test disconnected_nodes list def disconected_nodes(): - #graph = create_graph_database_connection(uri, userName, password, database) - graphDb_data_Access = graphDBdataAccess(graph) - nodes_list, total_nodes = graphDb_data_Access.list_unconnected_nodes() - print(nodes_list[0]["e"]["elementId"]) - status = "False" - - if total_nodes['total']>0: - status = "True" - else: - status = "False" - - return nodes_list[0]["e"]["elementId"], status - + #graph = create_graph_database_connection(uri, userName, password, database) + graphDb_data_Access = graphDBdataAccess(graph) + nodes_list, total_nodes = graphDb_data_Access.list_unconnected_nodes() + print(nodes_list[0]["e"]["elementId"]) + status = "False" + if total_nodes['total']>0: + status = "True" + else: + status = "False" + return nodes_list[0]["e"]["elementId"], status + #Test Delete delete_disconnected_nodes list def delete_disconected_nodes(lst_element_id): - print(f'disconnect elementid list {lst_element_id}') - #graph = create_graph_database_connection(uri, userName, password, database) - graphDb_data_Access = graphDBdataAccess(graph) - result = graphDb_data_Access.delete_unconnected_nodes(json.dumps(lst_element_id)) - print(f'delete disconnect api result {result}') - if not result: - return "True" - else: - return "False" + print(f'disconnect elementid list {lst_element_id}') + #graph = create_graph_database_connection(uri, userName, password, database) + graphDb_data_Access = graphDBdataAccess(graph) + result = graphDb_data_Access.delete_unconnected_nodes(json.dumps(lst_element_id)) + print(f'delete disconnect api result {result}') + if not result: + return "True" + else: + return "False" #Test Get Duplicate_nodes def get_duplicate_nodes(): - #graph = create_graph_database_connection(uri, userName, password, database) - graphDb_data_Access = graphDBdataAccess(graph) - nodes_list, total_nodes = graphDb_data_Access.get_duplicate_nodes_list() - if total_nodes['total']>0: - return "True" - else: - return "False" - + #graph = create_graph_database_connection(uri, userName, password, database) + graphDb_data_Access = graphDBdataAccess(graph) + nodes_list, total_nodes = graphDb_data_Access.get_duplicate_nodes_list() + if total_nodes['total']>0: + return "True" + else: + return "False" + #Test populate_graph_schema def test_populate_graph_schema_from_text(model): - result_schema = populate_graph_schema_from_text('When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble.', model, True) - print(result_schema) - return result_schema + result_schema = populate_graph_schema_from_text('When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble.', model, True) + print(result_schema) + return result_schema # def compare_graph_results(results): # """ @@ -200,44 +199,45 @@ def test_populate_graph_schema_from_text(model): # print(f"Result {i} differs from result {i+1}") def run_tests(): - final_list = [] - error_list = [] - models = ['openai-gpt-4o','gemini-1.5-pro'] - - for model_name in models: - try: - final_list.append(test_graph_from_file_local(model_name)) - final_list.append(test_graph_from_wikipedia(model_name)) - final_list.append(test_populate_graph_schema_from_text(model_name)) - final_list.append(test_graph_website(model_name)) - # final_list.append(test_graph_from_youtube_video(model_name)) - # final_list.append(test_chatbot_qna(model_name)) - # final_list.append(test_chatbot_qna(model_name, mode='vector')) - # final_list.append(test_chatbot_qna(model_name, mode='graph+vector+fulltext')) - except Exception as e: - error_list.append((model_name, str(e))) - # #Compare and log diffrences in graph results - # # compare_graph_results(final_list) # Pass the final_list to comapre_graph_results - # test_populate_graph_schema_from_text('openai-gpt-4o') - dis_elementid, dis_status = disconected_nodes() - lst_element_id = [dis_elementid] - delt = delete_disconected_nodes(lst_element_id) - dup = get_duplicate_nodes() - # schma = test_populate_graph_schema_from_text(model) - # Save final results to CSV - df = pd.DataFrame(final_list) - print(df) - df['execution_date'] = dt.today().strftime('%Y-%m-%d') - df['disconnected_nodes']=dis_status - df['get_duplicate_nodes']=dup - df['delete_disconected_nodes']=delt - # df['test_populate_graph_schema_from_text'] = schma - df.to_csv(f"Integration_TestResult_{dt.now().strftime('%Y%m%d_%H%M%S')}.csv", index=False) - - # Save error details to CSV - df_errors = pd.DataFrame(error_list, columns=['Model', 'Error']) - df_errors['execution_date'] = dt.today().strftime('%Y-%m-%d') - df_errors.to_csv(f"Error_details_{dt.now().strftime('%Y%m%d_%H%M%S')}.csv", index=False) + final_list = [] + error_list = [] + models = ['openai-gpt-3.5','openai-gpt-4o','openai-gpt-4o-mini','gemini-1.0-pro','gemini-1.5-pro','azure_ai_gpt_35','azure_ai_gpt_4o','ollama_llama3','groq_llama3_70b','anthropic_claude_3_5_sonnet','fireworks_v3p1_405b','bedrock_claude_3_5_sonnet'] + + for model_name in models: + try: + final_list.append(test_graph_from_file_local(model_name)) + final_list.append(test_graph_from_wikipedia(model_name)) + final_list.append(test_populate_graph_schema_from_text(model_name)) + final_list.append(test_graph_website(model_name)) + final_list.append(test_graph_from_youtube_video(model_name)) + final_list.append(test_chatbot_qna(model_name)) + final_list.append(test_chatbot_qna(model_name, mode='vector')) + final_list.append(test_chatbot_qna(model_name, mode='graph+vector+fulltext')) + except Exception as e: + error_list.append((model_name, str(e))) + # #Compare and log diffrences in graph results + # # compare_graph_results(final_list) # Pass the final_list to comapre_graph_results + # test_populate_graph_schema_from_text('openai-gpt-4o') + dis_elementid, dis_status = disconected_nodes() + lst_element_id = [dis_elementid] + delt = delete_disconected_nodes(lst_element_id) + dup = get_duplicate_nodes() + print(final_list) + # schma = test_populate_graph_schema_from_text(model) + # Save final results to CSV + df = pd.DataFrame(final_list) + print(df) + df['execution_date'] = dt.today().strftime('%Y-%m-%d') + df['disconnected_nodes']=dis_status + df['get_duplicate_nodes']=dup + df['delete_disconected_nodes']=delt + # df['test_populate_graph_schema_from_text'] = schma + df.to_csv(f"Integration_TestResult_{dt.now().strftime('%Y%m%d_%H%M%S')}.csv", index=False) + + # Save error details to CSV + df_errors = pd.DataFrame(error_list, columns=['Model', 'Error']) + df_errors['execution_date'] = dt.today().strftime('%Y-%m-%d') + df_errors.to_csv(f"Error_details_{dt.now().strftime('%Y%m%d_%H%M%S')}.csv", index=False) if __name__ == "__main__": - run_tests() \ No newline at end of file + run_tests() \ No newline at end of file From 801745e1ac773781cd8d7cd6fe9214c49e014df1 Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Mon, 16 Sep 2024 16:49:43 +0530 Subject: [PATCH 086/292] Integrate local search to chat details (#746) * added the commuties tab * removed unused variables * removed scipy libarary * added the mode check * Integrated the communities tab * added the cjheck * enabled the top entities mode * tabs order rearange * added the loader to sources tab for entity search+vector * fixed the chat mode per prop --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> --- backend/requirements.txt | 3 +- .../src/components/ChatBot/ChatInfoModal.tsx | 113 +++++- frontend/src/components/ChatBot/Chatbot.tsx | 10 +- .../src/components/ChatBot/Info/InfoModal.tsx | 360 ------------------ frontend/src/components/Content.tsx | 33 +- .../Local/DropZoneForSmallLayouts.tsx | 3 +- .../components/Graph/CheckboxSelection.tsx | 14 +- .../src/components/Graph/GraphViewModal.tsx | 31 +- .../Deduplication/index.tsx | 4 +- .../Popups/Settings/SchemaFromText.tsx | 1 - frontend/src/context/UserCredentials.tsx | 2 +- frontend/src/services/ChunkEntitiesInfo.ts | 9 +- frontend/src/types.ts | 12 +- frontend/src/utils/Constants.ts | 42 +- frontend/src/utils/Utils.ts | 122 ++++-- 15 files changed, 295 insertions(+), 464 deletions(-) delete mode 100644 frontend/src/components/ChatBot/Info/InfoModal.tsx diff --git a/backend/requirements.txt b/backend/requirements.txt index b83a76b82..8ae9195bb 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -140,7 +140,6 @@ requests==2.32.3 rsa==4.9 s3transfer==0.10.1 safetensors==0.4.1 -scipy==1.10.1 shapely==2.0.3 six==1.16.0 sniffio==1.3.1 @@ -179,4 +178,4 @@ sentence-transformers==3.0.1 google-cloud-logging==3.10.0 PyMuPDF==1.24.5 pypandoc==1.13 -graphdatascience==1.10 +graphdatascience==1.10 \ No newline at end of file diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index 3c6642665..2d4381f59 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -11,7 +11,12 @@ import { Banner, useMediaQuery, } from '@neo4j-ndl/react'; -import { DocumentDuplicateIconOutline, DocumentTextIconOutline } from '@neo4j-ndl/react/icons'; +import { + DocumentDuplicateIconOutline, + DocumentTextIconOutline, + ClipboardDocumentCheckIconOutline, + GlobeAltIconOutline, +} from '@neo4j-ndl/react/icons'; import '../../styling/info.css'; import Neo4jRetrievalLogo from '../../assets/images/Neo4jRetrievalLogo.png'; import wikipedialogo from '../../assets/images/wikipedia.svg'; @@ -20,6 +25,7 @@ import gcslogo from '../../assets/images/gcs.webp'; import s3logo from '../../assets/images/s3logo.png'; import { Chunk, + Community, Entity, ExtendedNode, ExtendedRelationship, @@ -34,10 +40,8 @@ import { chunkEntitiesAPI } from '../../services/ChunkEntitiesInfo'; import { useCredentials } from '../../context/UserCredentials'; import { calcWordColor } from '@neo4j-devtools/word-color'; import ReactMarkdown from 'react-markdown'; -import { GlobeAltIconOutline } from '@neo4j-ndl/react/icons'; -import { parseEntity, youtubeLinkValidation } from '../../utils/Utils'; +import { getLogo, parseEntity, youtubeLinkValidation } from '../../utils/Utils'; import { ThemeWrapperContext } from '../../context/ThemeWrapper'; -import { ClipboardDocumentCheckIconOutline } from '@neo4j-ndl/react/icons'; import { tokens } from '@neo4j-ndl/base'; const ChatInfoModal: React.FC = ({ @@ -55,6 +59,7 @@ const ChatInfoModal: React.FC = ({ const isTablet = useMediaQuery(`(min-width:${breakpoints.xs}) and (max-width: ${breakpoints.lg})`); const [activeTab, setActiveTab] = useState(error.length ? 10 : mode === 'graph' ? 4 : 3); const [infoEntities, setInfoEntities] = useState([]); + const [communities, setCommunities] = useState([]); const [loading, setLoading] = useState(false); const { userCredentials } = useCredentials(); const [nodes, setNodes] = useState([]); @@ -86,14 +91,25 @@ const ChatInfoModal: React.FC = ({ ], [copiedText, cypher_query] ); + useEffect(() => { if (mode != 'graph' || error?.trim() !== '') { - setLoading(true); - chunkEntitiesAPI(userCredentials as UserCredentials, chunk_ids.map((c) => c.id).join(',')) - .then((response) => { + (async () => { + setLoading(true); + try { + const response = await chunkEntitiesAPI( + userCredentials as UserCredentials, + chunk_ids.map((c) => c.id).join(','), + userCredentials?.database, + mode === 'entity search+vector' + ); + if (response.data.status === 'Failure') { + throw new Error(response.data.error); + } setInfoEntities(response.data.data.nodes); setNodes(response.data.data.nodes); setRelationships(response.data.data.relationships); + setCommunities(response.data.data.community_data); const chunks = response.data.data.chunk_data.map((chunk: any) => { const chunkScore = chunk_ids.find((chunkdetail) => chunkdetail.id === chunk.id); return { @@ -104,17 +120,17 @@ const ChatInfoModal: React.FC = ({ const sortedchunks = chunks.sort((a: any, b: any) => b.score - a.score); setChunks(sortedchunks); setLoading(false); - }) - .catch((error) => { + } catch (error) { console.error('Error fetching entities:', error); setLoading(false); - }); + } + })(); } - () => { setcopiedText(false); }; }, [chunk_ids, mode, error]); + const groupedEntities = useMemo<{ [key: string]: GroupedEntity }>(() => { return infoEntities.reduce((acc, entity) => { const { label, text } = parseEntity(entity); @@ -126,9 +142,11 @@ const ChatInfoModal: React.FC = ({ return acc; }, {} as Record; color: string }>); }, [infoEntities]); + const onChangeTabs = (tabId: number) => { setActiveTab(tabId); }; + const labelCounts = useMemo(() => { const counts: { [label: string]: number } = {}; for (let index = 0; index < infoEntities.length; index++) { @@ -139,6 +157,7 @@ const ChatInfoModal: React.FC = ({ } return counts; }, [infoEntities]); + const sortedLabels = useMemo(() => { return Object.keys(labelCounts).sort((a, b) => labelCounts[b] - labelCounts[a]); }, [labelCounts]); @@ -153,6 +172,7 @@ const ChatInfoModal: React.FC = ({ return ''; } }; + return ( @@ -176,7 +196,11 @@ const ChatInfoModal: React.FC = ({ ) : ( {mode != 'graph' ? Sources used : <>} - {mode === 'graph+vector' || mode === 'graph' || mode === 'graph+vector+fulltext' ? ( + {mode != 'graph' ? Chunks : <>} + {mode === 'graph+vector' || + mode === 'graph' || + mode === 'graph+vector+fulltext' || + mode === 'entity search+vector' ? ( Top Entities used ) : ( <> @@ -186,12 +210,46 @@ const ChatInfoModal: React.FC = ({ ) : ( <> )} - {mode != 'graph' ? Chunks : <>} + {mode === 'entity search+vector' ? Communities : <>} )} - {sources.length ? ( + {loading ? ( + + + + ) : mode === 'entity search+vector' && chunks.length ? ( +
    + {chunks + .map((c) => ({ fileName: c.fileName, fileSource: c.fileType })) + .map((s, index) => { + return ( +
  • +
    + {s.fileSource === 'local file' ? ( + + ) : ( + S3 Logo + )} + + {s.fileName} + +
    +
  • + ); + })} +
+ ) : sources.length ? (
    {sources.map((link, index) => { return ( @@ -436,6 +494,33 @@ const ChatInfoModal: React.FC = ({ className='min-h-40' /> + {mode === 'entity search+vector' ? ( + + {loading ? ( + + + + ) : ( +
    +
      + {communities.map((community, index) => ( +
    • +
      + + ID : + {community.id} + + {community.summary} +
      +
    • + ))} +
    +
    + )} +
    + ) : ( + <> + )} {activeTab == 4 && nodes.length && relationships.length ? ( diff --git a/frontend/src/components/ChatBot/Chatbot.tsx b/frontend/src/components/ChatBot/Chatbot.tsx index 7470dbd4d..5e931ad35 100644 --- a/frontend/src/components/ChatBot/Chatbot.tsx +++ b/frontend/src/components/ChatBot/Chatbot.tsx @@ -89,6 +89,7 @@ const Chatbot: FC = (props) => { cypher_query?: string; graphonly_entities?: []; error?: string; + entitiysearchonly_entities?: chunk[]; }, index = 0 ) => { @@ -119,6 +120,7 @@ const Chatbot: FC = (props) => { cypher_query: response?.cypher_query, graphonly_entities: response?.graphonly_entities, error: response.error, + entitiysearchonly_entities: response.entitiysearchonly_entities, }, ]); } else { @@ -141,6 +143,7 @@ const Chatbot: FC = (props) => { lastmsg.cypher_query = response.cypher_query; lastmsg.graphonly_entities = response.graphonly_entities; lastmsg.error = response.error; + lastmsg.entities = response.entitiysearchonly_entities; return msgs.map((msg, index) => { if (index === msgs.length - 1) { return lastmsg; @@ -174,6 +177,7 @@ const Chatbot: FC = (props) => { let cypher_query; let graphonly_entities; let error; + let entitiysearchonly_entities; const datetime = `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`; const userMessage = { id: Date.now(), user: 'user', message: inputMessage, datetime: datetime }; setListMessages([...listMessages, userMessage]); @@ -198,6 +202,7 @@ const Chatbot: FC = (props) => { chatingMode = chatresponse?.data?.data?.info?.mode; cypher_query = chatresponse?.data?.data?.info?.cypher_query ?? ''; graphonly_entities = chatresponse?.data.data.info.context ?? []; + entitiysearchonly_entities = chatresponse?.data.data.info.entities; error = chatresponse.data.data.info.error ?? ''; const finalbotReply = { reply: chatbotReply, @@ -212,6 +217,7 @@ const Chatbot: FC = (props) => { cypher_query, graphonly_entities, error, + entitiysearchonly_entities, }; simulateTypingEffect(finalbotReply); } catch (error) { @@ -349,7 +355,9 @@ const Chatbot: FC = (props) => { setModelModal(chat.model ?? ''); setSourcesModal(chat.sources ?? []); setResponseTime(chat.response_time ?? 0); - setChunkModal(chat.chunk_ids ?? []); + setChunkModal( + chat.mode === 'entity search+vector' ? chat.entities ?? [] : chat.chunk_ids ?? [] + ); setTokensUsed(chat.total_tokens ?? 0); setcypherQuery(chat.cypher_query ?? ''); setShowInfoModal(true); diff --git a/frontend/src/components/ChatBot/Info/InfoModal.tsx b/frontend/src/components/ChatBot/Info/InfoModal.tsx deleted file mode 100644 index 0d5b82a64..000000000 --- a/frontend/src/components/ChatBot/Info/InfoModal.tsx +++ /dev/null @@ -1,360 +0,0 @@ -import { Box, Typography, TextLink, Flex, Tabs, LoadingSpinner } from '@neo4j-ndl/react'; -import { DocumentTextIconOutline } from '@neo4j-ndl/react/icons'; -import '../../../styling/info.css'; -import Neo4jRetrievalLogo from '../../../assets/images/Neo4jRetrievalLogo.png'; -import wikipedialogo from '../../../assets/images/Wikipedia-logo-v2.svg'; -import youtubelogo from '../../../assets/images/youtube.png'; -import gcslogo from '../../../assets/images/gcs.webp'; -import s3logo from '../../../assets/images/s3logo.png'; -import { - Chunk, - Entity, - ExtendedNode, - ExtendedRelationship, - GroupedEntity, - UserCredentials, - chatInfoMessage, -} from '../../../types'; -import { useEffect, useMemo, useState } from 'react'; -import HoverableLink from '../../UI/HoverableLink'; -import GraphViewButton from '../../Graph/GraphViewButton'; -import { chunkEntitiesAPI } from '../../../services/ChunkEntitiesInfo'; -import { useCredentials } from '../../../context/UserCredentials'; -import { calcWordColor } from '@neo4j-devtools/word-color'; -import ReactMarkdown from 'react-markdown'; -import { GlobeAltIconOutline } from '@neo4j-ndl/react/icons'; -import { youtubeLinkValidation } from '../../../utils/Utils'; -const InfoModal: React.FC = ({ sources, model, total_tokens, response_time, chunk_ids }) => { - const [activeTab, setActiveTab] = useState(3); - const [infoEntities, setInfoEntities] = useState([]); - const [loading, setLoading] = useState(false); - const { userCredentials } = useCredentials(); - const [nodes, setNodes] = useState([]); - const [relationships, setRelationships] = useState([]); - const [chunks, setChunks] = useState([]); - const parseEntity = (entity: Entity) => { - const { labels, properties } = entity; - const [label] = labels; - const text = properties.id; - return { label, text }; - }; - useEffect(() => { - setLoading(true); - chunkEntitiesAPI(userCredentials as UserCredentials, chunk_ids.map((c) => c.id).join(',')) - .then((response) => { - setInfoEntities(response.data.data.nodes); - setNodes(response.data.data.nodes); - setRelationships(response.data.data.relationships); - const chunks = response.data.data.chunk_data.map((chunk: any) => { - const chunkScore = chunk_ids.find((chunkdetail) => chunkdetail.id === chunk.id); - return { - ...chunk, - score: chunkScore?.score, - }; - }); - const sortedchunks = chunks.sort((a: any, b: any) => b.score - a.score); - setChunks(sortedchunks); - setLoading(false); - }) - .catch((error) => { - console.error('Error fetching entities:', error); - setLoading(false); - }); - }, [chunk_ids]); - const groupedEntities = useMemo<{ [key: string]: GroupedEntity }>(() => { - return infoEntities.reduce((acc, entity) => { - const { label, text } = parseEntity(entity); - if (!acc[label]) { - const newColor = calcWordColor(label); - acc[label] = { texts: new Set(), color: newColor }; - } - acc[label].texts.add(text); - return acc; - }, {} as Record; color: string }>); - }, [infoEntities]); - const onChangeTabs = (tabId: number) => { - setActiveTab(tabId); - }; - const labelCounts = useMemo(() => { - const counts: { [label: string]: number } = {}; - for (let index = 0; index < infoEntities.length; index++) { - const entity = infoEntities[index]; - const { labels } = entity; - const [label] = labels; - counts[label] = counts[label] ? counts[label] + 1 : 1; - } - return counts; - }, [infoEntities]); - const sortedLabels = useMemo(() => { - return Object.keys(labelCounts).sort((a, b) => labelCounts[b] - labelCounts[a]); - }, [labelCounts]); - - const generateYouTubeLink = (url: string, startTime: string) => { - try { - const urlObj = new URL(url); - urlObj.searchParams.set('t', startTime); - return urlObj.toString(); - } catch (error) { - console.error('Invalid URL:', error); - return ''; - } - }; - return ( - - - - - Retrieval information - - To generate this response, in {response_time} seconds we used{' '} - {total_tokens} tokens with the model{' '} - {model}. - - - - - Sources used - Top Entities used - Chunks - - - - {sources.length ? ( -
      - {sources.map((link, index) => { - return ( -
    • - {link?.startsWith('http') || link?.startsWith('https') ? ( - <> - {link?.includes('wikipedia.org') && ( -
      - Wikipedia Logo - - - - {link} - - - -
      - )} - {link?.includes('storage.googleapis.com') && ( -
      - Google Cloud Storage Logo - - {decodeURIComponent(link).split('/').at(-1)?.split('?')[0] ?? 'GCS File'} - -
      - )} - {link?.startsWith('s3://') && ( -
      - S3 Logo - - {decodeURIComponent(link).split('/').at(-1) ?? 'S3 File'} - -
      - )} - {youtubeLinkValidation(link) && ( - <> -
      - - - - - {link} - - - -
      - - )} - {!link?.startsWith('s3://') && - !link?.includes('storage.googleapis.com') && - !link?.includes('wikipedia.org') && - !link?.includes('youtube.com') && ( -
      - - - {link} - -
      - )} - - ) : ( -
      - - - {link} - - {/* {chunks?.length > 0 && ( - - - Page{' '} - {chunks - .map((c) => c.page_number as number) - .sort((a, b) => a - b) - .join(', ')} - - )} */} -
      - )} -
    • - ); - })} -
    - ) : ( - No Sources Found - )} -
    - - {loading ? ( - - - - ) : Object.keys(groupedEntities).length > 0 ? ( -
      - {sortedLabels.map((label, index) => ( -
    • -
      - {label} ({labelCounts[label]}) -
      - - {Array.from(groupedEntities[label].texts).slice(0, 3).join(', ')} - -
    • - ))} -
    - ) : ( - No Entities Found - )} -
    - - {loading ? ( - - - - ) : chunks.length > 0 ? ( -
    -
      - {chunks.map((chunk) => ( -
    • - {chunk?.page_number ? ( - <> -
      - - - {/* {chunk?.fileName}, Page: {chunk?.page_number} */} - {chunk?.fileName} - -
      - Similarity Score: {chunk?.score} - - ) : chunk?.url && chunk?.start_time ? ( - <> -
      - - - - {chunk?.fileName} - - -
      - Similarity Score: {chunk?.score} - - ) : chunk?.url && chunk?.url.includes('wikipedia.org') ? ( - <> -
      - - {chunk?.fileName} -
      - Similarity Score: {chunk?.score} - - ) : chunk?.url && chunk?.url.includes('storage.googleapis.com') ? ( - <> -
      - - {chunk?.fileName} -
      - Similarity Score: {chunk?.score} - - ) : chunk?.url && chunk?.url.startsWith('s3://') ? ( - <> -
      - - {chunk?.fileName} -
      - - ) : chunk?.url && - !chunk?.url.startsWith('s3://') && - !chunk?.url.includes('storage.googleapis.com') && - !chunk?.url.includes('wikipedia.org') && - !chunk?.url.includes('youtube.com') ? ( - <> -
      - - - {chunk?.url} - -
      - Similarity Score: {chunk?.score} - - ) : ( - <> - )} - {chunk?.text} -
    • - ))} -
    -
    - ) : ( - No Chunks Found - )} -
    -
    - {activeTab == 4 && nodes.length && relationships.length ? ( - - - - ) : ( - <> - )} -
    - ); -}; -export default InfoModal; diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 648a86ac6..5862abe05 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -59,7 +59,8 @@ const Content: React.FC = ({ }); const [openGraphView, setOpenGraphView] = useState(false); const [inspectedName, setInspectedName] = useState(''); - const { setUserCredentials, userCredentials, connectionStatus, setConnectionStatus, isGdsActive, setGdsActive } = useCredentials(); + const { setUserCredentials, userCredentials, connectionStatus, setConnectionStatus, isGdsActive, setGdsActive } = + useCredentials(); const [showConfirmationModal, setshowConfirmationModal] = useState(false); const [extractLoading, setextractLoading] = useState(false); const [retryFile, setRetryFile] = useState(''); @@ -477,8 +478,9 @@ const Content: React.FC = ({ const handleOpenGraphClick = () => { const bloomUrl = process.env.VITE_BLOOM_URL; const uriCoded = userCredentials?.uri.replace(/:\d+$/, ''); - const connectURL = `${uriCoded?.split('//')[0]}//${userCredentials?.userName}@${uriCoded?.split('//')[1]}:${userCredentials?.port ?? '7687' - }`; + const connectURL = `${uriCoded?.split('//')[0]}//${userCredentials?.userName}@${uriCoded?.split('//')[1]}:${ + userCredentials?.port ?? '7687' + }`; const encodedURL = encodeURIComponent(connectURL); const replacedUrl = bloomUrl?.replace('{CONNECT_URL}', encodedURL); window.open(replacedUrl, '_blank'); @@ -488,10 +490,10 @@ const Content: React.FC = ({ isLeftExpanded && isRightExpanded ? 'contentWithExpansion' : isRightExpanded - ? 'contentWithChatBot' - : !isLeftExpanded && !isRightExpanded - ? 'w-[calc(100%-128px)]' - : 'contentWithDropzoneExpansion'; + ? 'contentWithChatBot' + : !isLeftExpanded && !isRightExpanded + ? 'w-[calc(100%-128px)]' + : 'contentWithDropzoneExpansion'; const handleGraphView = () => { setOpenGraphView(true); @@ -521,12 +523,12 @@ const Content: React.FC = ({ return prev.map((f) => { return f.name === filename ? { - ...f, - status: 'Reprocess', - processingProgress: isStartFromBegining ? 0 : f.processingProgress, - NodesCount: isStartFromBegining ? 0 : f.NodesCount, - relationshipCount: isStartFromBegining ? 0 : f.relationshipCount, - } + ...f, + status: 'Reprocess', + processingProgress: isStartFromBegining ? 0 : f.processingProgress, + NodesCount: isStartFromBegining ? 0 : f.NodesCount, + relationshipCount: isStartFromBegining ? 0 : f.relationshipCount, + } : f; }); }); @@ -815,8 +817,9 @@ const Content: React.FC = ({ handleGenerateGraph={processWaitingFilesOnRefresh} > diff --git a/frontend/src/components/DataSources/Local/DropZoneForSmallLayouts.tsx b/frontend/src/components/DataSources/Local/DropZoneForSmallLayouts.tsx index 21bd47240..17c97d0bc 100644 --- a/frontend/src/components/DataSources/Local/DropZoneForSmallLayouts.tsx +++ b/frontend/src/components/DataSources/Local/DropZoneForSmallLayouts.tsx @@ -142,7 +142,7 @@ export default function DropZoneForSmallLayouts() { uploadNextChunk(); }; - const { acceptedFiles, getRootProps, getInputProps } = useDropzone({ + const { getRootProps, getInputProps } = useDropzone({ accept: { 'application/pdf': ['.pdf'], 'image/*': ['.jpeg', '.jpg', '.png', '.svg'], @@ -214,7 +214,6 @@ export default function DropZoneForSmallLayouts() { setFilesData(copiedFilesData); } }; - console.log(acceptedFiles); return ( <>
    diff --git a/frontend/src/components/Graph/CheckboxSelection.tsx b/frontend/src/components/Graph/CheckboxSelection.tsx index 4f344d58c..b335a4324 100644 --- a/frontend/src/components/Graph/CheckboxSelection.tsx +++ b/frontend/src/components/Graph/CheckboxSelection.tsx @@ -18,12 +18,14 @@ const CheckboxSelection: React.FC = ({ graphType, loading, disabled={loading} onChange={() => handleChange('Entities')} /> - {isgds && ( handleChange('Communities')} - />)} + {isgds && ( + handleChange('Communities')} + /> + )}
); diff --git a/frontend/src/components/Graph/GraphViewModal.tsx b/frontend/src/components/Graph/GraphViewModal.tsx index 2a58adb25..c29ae1c75 100644 --- a/frontend/src/components/Graph/GraphViewModal.tsx +++ b/frontend/src/components/Graph/GraphViewModal.tsx @@ -98,10 +98,10 @@ const GraphViewModal: React.FunctionComponent = ({ graphType.includes('DocumentChunk') && graphType.includes('Entities') ? queryMap.DocChunkEntities : graphType.includes('DocumentChunk') - ? queryMap.DocChunks - : graphType.includes('Entities') - ? queryMap.Entities - : ''; + ? queryMap.DocChunks + : graphType.includes('Entities') + ? queryMap.Entities + : ''; // fit graph to original position const handleZoomToFit = () => { @@ -136,10 +136,10 @@ const GraphViewModal: React.FunctionComponent = ({ const nodeRelationshipData = viewPoint === graphLabels.showGraphView ? await graphQueryAPI( - userCredentials as UserCredentials, - graphQuery, - selectedRows?.map((f) => f.name) - ) + userCredentials as UserCredentials, + graphQuery, + selectedRows?.map((f) => f.name) + ) : await graphQueryAPI(userCredentials as UserCredentials, graphQuery, [inspectedName ?? '']); return nodeRelationshipData; } catch (error: any) { @@ -182,7 +182,7 @@ const GraphViewModal: React.FunctionComponent = ({ useEffect(() => { if (open) { setLoading(true); - setGraphType(intitalGraphType(isGdsActive)) + setGraphType(intitalGraphType(isGdsActive)); if (viewPoint !== 'chatInfoView') { graphApi(); } else { @@ -246,8 +246,8 @@ const GraphViewModal: React.FunctionComponent = ({ match && viewPoint === graphLabels.showGraphView ? 100 : match && viewPoint !== graphLabels.showGraphView - ? 50 - : graphLabels.nodeSize, + ? 50 + : graphLabels.nodeSize, }; }); // deactivating any active relationships @@ -264,7 +264,6 @@ const GraphViewModal: React.FunctionComponent = ({ [nodes] ); - // Unmounting the component if (!open) { return <>; @@ -357,8 +356,8 @@ const GraphViewModal: React.FunctionComponent = ({ isActive && viewPoint === graphLabels.showGraphView ? 100 : isActive && viewPoint !== graphLabels.showGraphView - ? 50 - : graphLabels.nodeSize, + ? 50 + : graphLabels.nodeSize, }; }); // deactivating any active relationships @@ -399,10 +398,6 @@ const GraphViewModal: React.FunctionComponent = ({ setRelationships(updatedRelations); setNodes(updatedNodes); }; - - console.log('rels', relationships); - - console.log('nodes', nodes); return ( <> { setDuplicateNodes((prev) => { return prev.map((d) => - d.e.elementId === nodeid + (d.e.elementId === nodeid ? { ...d, similar: d.similar.filter((n) => n.elementId != similarNodeId), } - : d + : d) ); }); }; diff --git a/frontend/src/components/Popups/Settings/SchemaFromText.tsx b/frontend/src/components/Popups/Settings/SchemaFromText.tsx index 8ebc15020..914d9580c 100644 --- a/frontend/src/components/Popups/Settings/SchemaFromText.tsx +++ b/frontend/src/components/Popups/Settings/SchemaFromText.tsx @@ -27,7 +27,6 @@ const SchemaFromTextDialog = ({ try { setloading(true); const response = await getNodeLabelsAndRelTypesFromText(model, userText, isSchema); - console.log({ response }); setloading(false); if (response.data.status === 'Success') { if (response.data?.data?.labels.length) { diff --git a/frontend/src/context/UserCredentials.tsx b/frontend/src/context/UserCredentials.tsx index 8530cacfa..1b5eda2da 100644 --- a/frontend/src/context/UserCredentials.tsx +++ b/frontend/src/context/UserCredentials.tsx @@ -28,7 +28,7 @@ const UserCredentialsWrapper: FunctionComponent = (props) => { setGdsActive, connectionStatus, setConnectionStatus, - } + }; return {props.children}; }; diff --git a/frontend/src/services/ChunkEntitiesInfo.ts b/frontend/src/services/ChunkEntitiesInfo.ts index aa133c815..f69ddd3aa 100644 --- a/frontend/src/services/ChunkEntitiesInfo.ts +++ b/frontend/src/services/ChunkEntitiesInfo.ts @@ -1,13 +1,20 @@ import { ChatInfo_APIResponse, UserCredentials } from '../types'; import api from '../API/Index'; -const chunkEntitiesAPI = async (userCredentials: UserCredentials, chunk_ids: string) => { +const chunkEntitiesAPI = async ( + userCredentials: UserCredentials, + chunk_ids: string, + database: string = 'neo4j', + is_entity: boolean = false +) => { try { const formData = new FormData(); formData.append('uri', userCredentials?.uri ?? ''); formData.append('userName', userCredentials?.userName ?? ''); formData.append('password', userCredentials?.password ?? ''); formData.append('chunk_ids', chunk_ids); + formData.append('database', database); + formData.append('is_entity', String(is_entity)); const response: ChatInfo_APIResponse = await api.post(`/chunk_entities`, formData, { headers: { diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 625e90037..d22ce02fb 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -84,7 +84,7 @@ export type UploadParams = { originalname: string; } & { [key: string]: any }; -export type FormDataParams = ExtractParams | UploadParams; +export type ForDataParams = ExtractParams | UploadParams; export interface DropdownProps { onSelect: (option: OptionType | null | void) => void; @@ -223,6 +223,7 @@ export interface Messages { cypher_query?: string; graphonly_entities?: []; error?: string; + entities?: chunk[]; } export type ChatbotProps = { @@ -464,7 +465,13 @@ export type Entity = { id: string; }; }; - +export type Community = { + id: string; + summary: string; + weight: number; + level: number; + community_rank: number; +}; export type GroupedEntity = { texts: Set; color: string; @@ -502,6 +509,7 @@ export interface Chunk { url?: string; fileSource: string; score?: string; + fileType: string; } export interface SpeechSynthesisProps { diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index a3f77c134..cf2c2619c 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -36,30 +36,38 @@ export const llms = process.env?.VITE_LLM_MODELS?.trim() != '' ? (process.env.VITE_LLM_MODELS?.split(',') as string[]) : [ - 'diffbot', - 'openai-gpt-3.5', - 'openai-gpt-4o', - 'openai-gpt-4o-mini', - 'gemini-1.0-pro', - 'gemini-1.5-pro', - 'azure_ai_gpt_35', - 'azure_ai_gpt_4o', - 'ollama_llama3', - 'groq_llama3_70b', - 'anthropic_claude_3_5_sonnet', - 'fireworks_v3p1_405b', - 'bedrock_claude_3_5_sonnet', - ]; + 'diffbot', + 'openai-gpt-3.5', + 'openai-gpt-4o', + 'openai-gpt-4o-mini', + 'gemini-1.0-pro', + 'gemini-1.5-pro', + 'azure_ai_gpt_35', + 'azure_ai_gpt_4o', + 'ollama_llama3', + 'groq_llama3_70b', + 'anthropic_claude_3_5_sonnet', + 'fireworks_v3p1_405b', + 'bedrock_claude_3_5_sonnet', + ]; export const defaultLLM = llms?.includes('openai-gpt-4o') ? 'openai-gpt-4o' : llms?.includes('gemini-1.0-pro') - ? 'gemini-1.0-pro' - : 'diffbot'; + ? 'gemini-1.0-pro' + : 'diffbot'; export const chatModes = process.env?.VITE_CHAT_MODES?.trim() != '' ? process.env.VITE_CHAT_MODES?.split(',') - : ['vector', 'graph', 'graph+vector', 'fulltext', 'graph+vector+fulltext', 'entity search+vector', 'global community']; + : [ + 'vector', + 'graph', + 'graph+vector', + 'fulltext', + 'graph+vector+fulltext', + 'entity search+vector', + 'global community', + ]; export const chunkSize = process.env.VITE_CHUNK_SIZE ? parseInt(process.env.VITE_CHUNK_SIZE) : 1 * 1024 * 1024; export const timeperpage = process.env.VITE_TIME_PER_PAGE ? parseInt(process.env.VITE_TIME_PER_PAGE) : 50; export const timePerByte = 0.2; diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index f332abb6e..7a6283c27 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -1,6 +1,24 @@ import { calcWordColor } from '@neo4j-devtools/word-color'; import type { Relationship } from '@neo4j-nvl/base'; -import { CustomFile, Entity, ExtendedNode, ExtendedRelationship, GraphType, Messages, Scheme, SourceNode, UserCredentials } from '../types'; +import { + CustomFile, + Entity, + ExtendedNode, + ExtendedRelationship, + GraphType, + Messages, + Scheme, + SourceNode, + UserCredentials, +} from '../types'; +import Wikipediadarkmode from '../assets/images/wikipedia-darkmode.svg'; +import Wikipediadlogo from '../assets/images/wikipedia.svg'; +import webdarklogo from '../assets/images/web-darkmode.svg'; +import weblogo from '../assets/images/web.svg'; +import youtubedarklogo from '../assets/images/youtube-darkmode.svg'; +import youtubelightlogo from '../assets/images/youtube-lightmode.svg'; +import s3logo from '../assets/images/s3logo.png'; +import gcslogo from '../assets/images/gcs.webp'; // Get the Url export const url = () => { @@ -172,27 +190,33 @@ export const processGraphData = (neoNodes: ExtendedNode[], neoRels: ExtendedRela }; /** -* Filters nodes, relationships, and scheme based on the selected graph types. -* -* @param graphType - An array of graph types to filter by (e.g., 'DocumentChunk', 'Entities', 'Communities'). -* @param allNodes - An array of all nodes present in the graph. -* @param allRelationships - An array of all relationships in the graph. -* @param scheme - The scheme object containing node and relationship information. -* @returns An object containing filtered nodes, relationships, and scheme based on the selected graph types. -*/ + * Filters nodes, relationships, and scheme based on the selected graph types. + * + * @param graphType - An array of graph types to filter by (e.g., 'DocumentChunk', 'Entities', 'Communities'). + * @param allNodes - An array of all nodes present in the graph. + * @param allRelationships - An array of all relationships in the graph. + * @param scheme - The scheme object containing node and relationship information. + * @returns An object containing filtered nodes, relationships, and scheme based on the selected graph types. + */ export const filterData = ( graphType: GraphType[], allNodes: ExtendedNode[], allRelationships: Relationship[], scheme: Scheme, - isGdsActive: boolean, + isGdsActive: boolean ) => { let filteredNodes: ExtendedNode[] = []; let filteredRelations: Relationship[] = []; let filteredScheme: Scheme = {}; - const entityTypes = Object.keys(scheme).filter((type) => type !== 'Document' && type !== 'Chunk' && type !== '__Community__'); + const entityTypes = Object.keys(scheme).filter( + (type) => type !== 'Document' && type !== 'Chunk' && type !== '__Community__' + ); // Only Document + Chunk - if (graphType.includes('DocumentChunk') && !graphType.includes('Entities') && (!graphType.includes('Communities') || !isGdsActive)) { + if ( + graphType.includes('DocumentChunk') && + !graphType.includes('Entities') && + (!graphType.includes('Communities') || !isGdsActive) + ) { filteredNodes = allNodes.filter( (node) => (node.labels.includes('Document') && node.properties.fileName) || node.labels.includes('Chunk') ); @@ -205,7 +229,11 @@ export const filterData = ( ); filteredScheme = { Document: scheme.Document, Chunk: scheme.Chunk }; // Only Entity - } else if (graphType.includes('Entities') && !graphType.includes('DocumentChunk') && (!graphType.includes('Communities') || !isGdsActive)) { + } else if ( + graphType.includes('Entities') && + !graphType.includes('DocumentChunk') && + (!graphType.includes('Communities') || !isGdsActive) + ) { const entityNodes = allNodes.filter((node) => !node.labels.includes('Document') && !node.labels.includes('Chunk')); filteredNodes = entityNodes ? entityNodes : []; const nodeIds = new Set(filteredNodes.map((node) => node.id)); @@ -217,7 +245,12 @@ export const filterData = ( ); filteredScheme = Object.fromEntries(entityTypes.map((key) => [key, scheme[key]])) as Scheme; // Only Communities - } else if (graphType.includes('Communities') && !graphType.includes('DocumentChunk') && !graphType.includes('Entities') && isGdsActive) { + } else if ( + graphType.includes('Communities') && + !graphType.includes('DocumentChunk') && + !graphType.includes('Entities') && + isGdsActive + ) { filteredNodes = allNodes.filter((node) => node.labels.includes('__Community__')); const nodeIds = new Set(filteredNodes.map((node) => node.id)); filteredRelations = allRelationships.filter( @@ -226,10 +259,16 @@ export const filterData = ( ); filteredScheme = { __Community__: scheme.__Community__ }; // Document + Chunk + Entity - } else if (graphType.includes('DocumentChunk') && graphType.includes('Entities') && (!graphType.includes('Communities') || !isGdsActive)) { + } else if ( + graphType.includes('DocumentChunk') && + graphType.includes('Entities') && + (!graphType.includes('Communities') || !isGdsActive) + ) { filteredNodes = allNodes.filter( (node) => - (node.labels.includes('Document') && node.properties.fileName) || node.labels.includes('Chunk') || !node.labels.includes('Document') && !node.labels.includes('Chunk') && !node.labels.includes('__Community__') + (node.labels.includes('Document') && node.properties.fileName) || + node.labels.includes('Chunk') || + (!node.labels.includes('Document') && !node.labels.includes('Chunk') && !node.labels.includes('__Community__')) ); const nodeIds = new Set(filteredNodes.map((node) => node.id)); filteredRelations = allRelationships.filter( @@ -238,9 +277,18 @@ export const filterData = ( nodeIds.has(rel.from) && nodeIds.has(rel.to) ); - filteredScheme = { Document: scheme.Document, Chunk: scheme.Chunk, ...Object.fromEntries(entityTypes.map((key) => [key, scheme[key]])) }; + filteredScheme = { + Document: scheme.Document, + Chunk: scheme.Chunk, + ...Object.fromEntries(entityTypes.map((key) => [key, scheme[key]])), + }; // Entities + Communities - } else if (graphType.includes('Entities') && graphType.includes('Communities') && !graphType.includes('DocumentChunk') && isGdsActive) { + } else if ( + graphType.includes('Entities') && + graphType.includes('Communities') && + !graphType.includes('DocumentChunk') && + isGdsActive + ) { const entityNodes = allNodes.filter((node) => !node.labels.includes('Document') && !node.labels.includes('Chunk')); const communityNodes = allNodes.filter((node) => node.labels.includes('__Community__')); filteredNodes = [...entityNodes, ...communityNodes]; @@ -253,10 +301,15 @@ export const filterData = ( ); filteredScheme = { ...Object.fromEntries(entityTypes.map((key) => [key, scheme[key]])), - __Community__: scheme.__Community__ + __Community__: scheme.__Community__, }; // Document + Chunk + Communities - } else if (graphType.includes('DocumentChunk') && graphType.includes('Communities') && !graphType.includes('Entities') && isGdsActive) { + } else if ( + graphType.includes('DocumentChunk') && + graphType.includes('Communities') && + !graphType.includes('Entities') && + isGdsActive + ) { const documentChunkNodes = allNodes.filter( (node) => (node.labels.includes('Document') && node.properties.fileName) || node.labels.includes('Chunk') ); @@ -265,13 +318,20 @@ export const filterData = ( const nodeIds = new Set(filteredNodes.map((node) => node.id)); filteredRelations = allRelationships.filter( (rel) => - ['PART_OF', 'FIRST_CHUNK', 'SIMILAR', 'NEXT_CHUNK', 'IN_COMMUNITY', 'PARENT_COMMUNITY'].includes(rel.caption ?? '') && + ['PART_OF', 'FIRST_CHUNK', 'SIMILAR', 'NEXT_CHUNK', 'IN_COMMUNITY', 'PARENT_COMMUNITY'].includes( + rel.caption ?? '' + ) && nodeIds.has(rel.from) && nodeIds.has(rel.to) ); filteredScheme = { Document: scheme.Document, Chunk: scheme.Chunk, __Community__: scheme.__Community__ }; // Document + Chunk + Entity + Communities (All types) - } else if (graphType.includes('DocumentChunk') && graphType.includes('Entities') && graphType.includes('Communities') && isGdsActive) { + } else if ( + graphType.includes('DocumentChunk') && + graphType.includes('Entities') && + graphType.includes('Communities') && + isGdsActive + ) { filteredNodes = allNodes; filteredRelations = allRelationships; filteredScheme = scheme; @@ -349,3 +409,21 @@ export const capitalizeWithPlus = (s: string) => { .map((s) => capitalize(s)) .join('+'); }; +export const getLogo = (mode: string): Record => { + if (mode === 'light') { + return { + Wikipedia: Wikipediadarkmode, + 'web-url': webdarklogo, + 's3 bucket': s3logo, + youtube: youtubedarklogo, + 'gcs bucket': gcslogo, + }; + } + return { + Wikipedia: Wikipediadlogo, + 'web-url': weblogo, + 's3 bucket': s3logo, + youtube: youtubelightlogo, + 'gcs bucket': gcslogo, + }; +}; From 107f065df31dbd4d83d20cd4c8782ec5893d566b Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Mon, 16 Sep 2024 12:01:18 +0000 Subject: [PATCH 087/292] removal of unused code --- frontend/src/components/FileTable.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/FileTable.tsx b/frontend/src/components/FileTable.tsx index 04e2a8841..f6a0c0c08 100644 --- a/frontend/src/components/FileTable.tsx +++ b/frontend/src/components/FileTable.tsx @@ -35,7 +35,7 @@ import { } from '../utils/Utils'; import { SourceNode, CustomFile, FileTableProps, UserCredentials, statusupdate, ChildRef } from '../types'; import { useCredentials } from '../context/UserCredentials'; -import { ArrowPathIconSolid, MagnifyingGlassCircleIconSolid } from '@neo4j-ndl/react/icons'; +import {MagnifyingGlassCircleIconSolid } from '@neo4j-ndl/react/icons'; import CustomProgressBar from './UI/CustomProgressBar'; import subscribe from '../services/PollingAPI'; import { triggerStatusUpdateAPI } from '../services/ServerSideStatusUpdateAPI'; @@ -49,7 +49,7 @@ import IndeterminateCheckbox from './UI/CustomCheckBox'; import { showErrorToast, showNormalToast } from '../utils/toasts'; let onlyfortheFirstRender = true; const FileTable = forwardRef((props, ref) => { - const { isExpanded, connectionStatus, setConnectionStatus, onInspect, onRetry } = props; + const { isExpanded, connectionStatus, setConnectionStatus, onInspect } = props; const { filesData, setFilesData, model, rowSelection, setRowSelection, setSelectedRows, setProcessedCount, queue } = useFileContext(); const { userCredentials } = useCredentials(); From 8f0a706062cc8f933df01fb446df79838c482596 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Mon, 16 Sep 2024 12:06:17 +0000 Subject: [PATCH 088/292] removed entity label --- backend/src/chunkid_entities.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backend/src/chunkid_entities.py b/backend/src/chunkid_entities.py index 89ea069f6..30b1c15a9 100644 --- a/backend/src/chunkid_entities.py +++ b/backend/src/chunkid_entities.py @@ -95,6 +95,10 @@ def remove_duplicate_nodes(nodes,property="element_id"): for node in nodes: element_id = node[property] if element_id not in seen_element_ids: + if "labels" in node.keys(): + labels = set(node["labels"]) + labels.discard("__Entity__") + node["labels"] = list(labels) unique_nodes.append(node) seen_element_ids.add(element_id) From bc09b864fe4ba1b4ad87b8130e675738a6370b9b Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Mon, 16 Sep 2024 18:28:27 +0530 Subject: [PATCH 089/292] Added Description to chat mode menu (#743) * added tooltips to chat mode menu * addition of description to menu * 741-tooltips-to-selectOptions * menu changes * acommunities name change * close changes * name changes * format fixes --- frontend/src/App.css | 26 +++++-- .../src/components/ChatBot/ChatModeToggle.tsx | 78 +++++++++---------- frontend/src/components/Graph/LegendsChip.tsx | 11 ++- frontend/src/components/Layout/SideNav.tsx | 2 + .../Deduplication/index.tsx | 4 +- frontend/src/components/UI/Menu.tsx | 31 ++++---- frontend/src/types.ts | 2 +- frontend/src/utils/Constants.ts | 51 ++++++++++-- frontend/src/utils/Utils.ts | 21 ++++- 9 files changed, 150 insertions(+), 76 deletions(-) diff --git a/frontend/src/App.css b/frontend/src/App.css index fe285c972..615b8559b 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -121,7 +121,8 @@ height: 55px; object-fit: contain; } -.webImg{ + +.webImg { width: 80px; height: 80px; } @@ -240,9 +241,11 @@ .ndl-widget-content>div { overflow-wrap: break-word } -.word-break{ + +.word-break { word-break: break-word; } + .cellClass { width: 100%; height: 100%; @@ -345,22 +348,28 @@ margin-bottom: 0 !important; } -.node_label__value-container--has-value ,.relationship_label__value-container--has-value{ +.node_label__value-container--has-value, +.relationship_label__value-container--has-value { max-height: 215px; overflow-y: scroll !important; scrollbar-width: thin; } -.entity_extraction_Tab_node_label__value-container--has-value,.entity_extraction_Tab_relationship_label__value-container--has-value{ + +.entity_extraction_Tab_node_label__value-container--has-value, +.entity_extraction_Tab_relationship_label__value-container--has-value { max-height: 100px; overflow-y: scroll !important; scrollbar-width: thin; } -.tablet_entity_extraction_Tab_node_label__value-container--has-value,.tablet_entity_extraction_Tab_relationship_label__value-container--has-value{ + +.tablet_entity_extraction_Tab_node_label__value-container--has-value, +.tablet_entity_extraction_Tab_relationship_label__value-container--has-value { max-height: 80px; overflow-y: scroll !important; scrollbar-width: thin; } -.widthunset{ + +.widthunset { width: initial !important; height: initial !important; } @@ -372,4 +381,9 @@ .text-input-container.search-initiated { width: 60dvh; +} + +.custom-menu { + min-width: 250px; + max-width: 300px; } \ No newline at end of file diff --git a/frontend/src/components/ChatBot/ChatModeToggle.tsx b/frontend/src/components/ChatBot/ChatModeToggle.tsx index 6315394af..a0ebe879a 100644 --- a/frontend/src/components/ChatBot/ChatModeToggle.tsx +++ b/frontend/src/components/ChatBot/ChatModeToggle.tsx @@ -1,4 +1,4 @@ -import { StatusIndicator } from '@neo4j-ndl/react'; +import { StatusIndicator, Typography } from '@neo4j-ndl/react'; import { useMemo } from 'react'; import { useFileContext } from '../../context/UsersFiles'; import CustomMenu from '../UI/Menu'; @@ -22,6 +22,39 @@ export default function ChatModeToggle({ const { setchatMode, chatMode, postProcessingTasks } = useFileContext(); const isCommunityAllowed = postProcessingTasks.includes('create_communities'); const { isGdsActive } = useCredentials(); + const memoizedChatModes = useMemo(() => { + return isGdsActive && isCommunityAllowed + ? chatModes + : chatModes?.filter((m) => !m.mode.includes('entity search+vector')); + }, [isGdsActive, isCommunityAllowed]); + const menuItems = useMemo(() => { + return memoizedChatModes?.map((m) => ({ + title: ( +
+ + {m.mode.includes('+') ? capitalizeWithPlus(m.mode) : capitalize(m.mode)} + +
+ {m.description} +
+
+ ), + onClick: () => { + setchatMode(m.mode); + closeHandler(); // Close the menu after setting the chat mode + }, + disabledCondition: false, + description: ( + + {chatMode === m.mode && ( + <> + Selected + + )} + + ), + })); + }, [chatMode, memoizedChatModes, setchatMode, closeHandler]); return ( { - if (isGdsActive && isCommunityAllowed) { - return chatModes?.map((m) => { - return { - title: m.includes('+') ? capitalizeWithPlus(m) : capitalize(m), - onClick: () => { - setchatMode(m); - }, - disabledCondition: false, - description: ( - - {chatMode === m && ( - <> - Selected - - )} - - ), - }; - }); - } - return chatModes - ?.filter((s) => !s.includes('community')) - ?.map((m) => { - return { - title: m.includes('+') ? capitalizeWithPlus(m) : capitalize(m), - onClick: () => { - setchatMode(m); - }, - disabledCondition: false, - description: ( - - {chatMode === m && ( - <> - Selected - - )} - - ), - }; - }); - }, [chatMode, chatModes, isCommunityAllowed, isGdsActive])} + items={menuItems} /> ); } diff --git a/frontend/src/components/Graph/LegendsChip.tsx b/frontend/src/components/Graph/LegendsChip.tsx index 2ab9c7b40..832150fad 100644 --- a/frontend/src/components/Graph/LegendsChip.tsx +++ b/frontend/src/components/Graph/LegendsChip.tsx @@ -1,6 +1,15 @@ import { LegendChipProps } from '../../types'; +import { graphLabels } from '../../utils/Constants'; import Legend from '../UI/Legend'; export const LegendsChip: React.FunctionComponent = ({ scheme, label, type, count, onClick }) => { - return ; + return ( + + ); }; diff --git a/frontend/src/components/Layout/SideNav.tsx b/frontend/src/components/Layout/SideNav.tsx index ddc29dd02..bdc43c8be 100644 --- a/frontend/src/components/Layout/SideNav.tsx +++ b/frontend/src/components/Layout/SideNav.tsx @@ -203,6 +203,7 @@ const SideNav: React.FC = ({ {!isChatModalOpen && ( { setchatModeAnchor(e.currentTarget); setshowChatMode(true); @@ -217,6 +218,7 @@ const SideNav: React.FC = ({ closeHandler={() => setshowChatMode(false)} menuAnchor={chatModeAnchor} disableBackdrop={true} + anchorPortal={true} > } diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx index f5a021e30..36fcff3d1 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx @@ -80,12 +80,12 @@ export default function DeduplicationTab() { const onRemove = (nodeid: string, similarNodeId: string) => { setDuplicateNodes((prev) => { return prev.map((d) => - (d.e.elementId === nodeid + d.e.elementId === nodeid ? { ...d, similar: d.similar.filter((n) => n.elementId != similarNodeId), } - : d) + : d ); }); }; diff --git a/frontend/src/components/UI/Menu.tsx b/frontend/src/components/UI/Menu.tsx index 4cfd1e238..62cc25095 100644 --- a/frontend/src/components/UI/Menu.tsx +++ b/frontend/src/components/UI/Menu.tsx @@ -1,6 +1,5 @@ import { Menu } from '@neo4j-ndl/react'; import { Menuitems, Origin } from '../../types'; - export default function CustomMenu({ open, closeHandler, @@ -23,25 +22,29 @@ export default function CustomMenu({ return ( { + closeHandler(); + }} anchorOrigin={anchorOrigin} transformOrigin={transformOrigin} anchorPortal={anchorPortal} anchorEl={MenuAnchor} disableBackdrop={disableBackdrop} + className='custom-menu' > - {items?.map((i, idx) => { - return ( - - ); - })} + {items?.map((i, idx) => ( + { + i.onClick(); + closeHandler(); + }} + disabled={i.disabledCondition} + className={i.isSelected ? i.selectedClassName : ''} + description={i.description} + /> + ))} ); } diff --git a/frontend/src/types.ts b/frontend/src/types.ts index d22ce02fb..8b00b1695 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -534,7 +534,7 @@ export interface SettingsModalProps { onClear?: () => void; } export interface Menuitems { - title: string; + title: string | JSX.Element; onClick: () => void; disabledCondition: boolean; description?: string | React.ReactNode; diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index cf2c2619c..e5cb806c8 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -1,5 +1,6 @@ import { NvlOptions } from '@neo4j-nvl/base'; import { GraphType, OptionType } from '../types'; +import { getDescriptionForChatMode } from './Utils'; export const document = `+ [docs]`; @@ -28,10 +29,12 @@ export const docChunkEntities = `+[chunks] + collect { MATCH p=(c)-[:SIMILAR]-() RETURN p } // similar-chunks //chunks with entities + collect { OPTIONAL MATCH p=(c:Chunk)-[:HAS_ENTITY]->(e)-[*0..1]-(:!Chunk) RETURN p }`; + export const APP_SOURCES = process.env.VITE_REACT_APP_SOURCES !== '' ? (process.env.VITE_REACT_APP_SOURCES?.split(',') as string[]) : ['gcs', 's3', 'local', 'wiki', 'youtube', 'web']; + export const llms = process.env?.VITE_LLM_MODELS?.trim() != '' ? (process.env.VITE_LLM_MODELS?.split(',') as string[]) @@ -56,18 +59,50 @@ export const defaultLLM = llms?.includes('openai-gpt-4o') : llms?.includes('gemini-1.0-pro') ? 'gemini-1.0-pro' : 'diffbot'; + +// export const chatModes = +// process.env?.VITE_CHAT_MODES?.trim() != '' +// ? process.env.VITE_CHAT_MODES?.split(',') +// : ['vector', 'graph', 'graph+vector', 'fulltext', 'graph+vector+fulltext', 'local community', 'global community']; + export const chatModes = process.env?.VITE_CHAT_MODES?.trim() != '' - ? process.env.VITE_CHAT_MODES?.split(',') + ? process.env.VITE_CHAT_MODES?.split(',').map((mode) => ({ + mode: mode.trim(), + description: getDescriptionForChatMode(mode.trim()), + })) : [ - 'vector', - 'graph', - 'graph+vector', - 'fulltext', - 'graph+vector+fulltext', - 'entity search+vector', - 'global community', + { + mode: 'vector', + description: 'Utilizes vector indexing on text chunks to enable semantic similarity search.', + }, + { + mode: 'graph', + description: + 'Leverages text-to-cypher translation to query a database and retrieve relevant data, ensuring a highly targeted and contextually accurate response.', + }, + { + mode: 'graph+vector', + description: + 'Combines vector indexing on text chunks with graph connections, enhancing search results with contextual relevance by considering relationships between concepts.', + }, + { + mode: 'fulltext', + description: + 'Employs a fulltext index on text chunks for rapid keyword-based search, efficiently identifying documents containing specific words or phrases.', + }, + { + mode: 'graph+vector+fulltext', + description: + 'Merges vector indexing, graph connections, and fulltext indexing for a comprehensive search approach, combining semantic similarity, contextual relevance, and keyword-based search for optimal results.', + }, + { + mode: 'entity search+vector', + description: + 'Combines entity node vector indexing with graph connections for accurate entity-based search, providing the most relevant response.', + }, ]; + export const chunkSize = process.env.VITE_CHUNK_SIZE ? parseInt(process.env.VITE_CHUNK_SIZE) : 1 * 1024 * 1024; export const timeperpage = process.env.VITE_TIME_PER_PAGE ? parseInt(process.env.VITE_TIME_PER_PAGE) : 50; export const timePerByte = 0.2; diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index 7a6283c27..3eb5f7ab7 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -392,7 +392,7 @@ export const isFileCompleted = (waitingFile: CustomFile, item: SourceNode) => waitingFile && item.status === 'Completed'; export const calculateProcessedCount = (prev: number, batchSize: number) => - (prev === batchSize ? batchSize - 1 : prev + 1); + prev === batchSize ? batchSize - 1 : prev + 1; export const isProcessingFileValid = (item: SourceNode, userCredentials: UserCredentials) => { return item.status === 'Processing' && item.fileName != undefined && userCredentials && userCredentials.database; @@ -409,6 +409,25 @@ export const capitalizeWithPlus = (s: string) => { .map((s) => capitalize(s)) .join('+'); }; + +export const getDescriptionForChatMode = (mode: string): string => { + switch (mode.toLowerCase()) { + case 'vector': + return 'Utilizes vector indexing on text chunks to enable semantic similarity search.'; + case 'graph': + return 'Leverages text-to-cypher translation to query a database and retrieve relevant data, ensuring a highly targeted and contextually accurate response.'; + case 'graph+vector': + return 'Combines vector indexing on text chunks with graph connections, enhancing search results with contextual relevance by considering relationships between concepts.'; + case 'fulltext': + return 'Employs a fulltext index on text chunks for rapid keyword-based search, efficiently identifying documents containing specific words or phrases.'; + case 'graph+vector+fulltext': + return 'Merges vector indexing, graph connections, and fulltext indexing for a comprehensive search approach, combining semantic similarity, contextual relevance, and keyword-based search for optimal results.'; + case 'entity search+vector': + return 'Combines entity node vector indexing with graph connections for accurate entity-based search, providing the most relevant response.'; + default: + return 'Chat mode description not available'; // Fallback description + } +}; export const getLogo = (mode: string): Record => { if (mode === 'light') { return { From 337cd257491d698e8f173eb172df5f9a09588576 Mon Sep 17 00:00:00 2001 From: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Date: Mon, 16 Sep 2024 13:50:48 +0000 Subject: [PATCH 090/292] Update log_struct method to add severity --- backend/score.py | 24 ++++++++++++------------ backend/src/logger.py | 6 +++--- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/backend/score.py b/backend/score.py index 8f62b29f1..bd1be1ea7 100644 --- a/backend/score.py +++ b/backend/score.py @@ -115,7 +115,7 @@ async def create_source_knowledge_graph_url( message = f"Source Node created successfully for source type: {source_type} and source: {source}" json_obj = {'api_name':'url_scan','db_url':uri,'url_scanned_file':lst_file_name, 'source_url':source_url, 'wiki_query':wiki_query, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(json_obj) + logger.log_struct(json_obj, "INFO") return create_api_response("Success",message=message,success_count=success_count,failed_count=failed_count,file_name=lst_file_name) except Exception as e: error_message = str(e) @@ -203,7 +203,7 @@ async def extract_knowledge_graph_from_file( result['wiki_query'] = wiki_query result['source_type'] = source_type result['logging_time'] = formatted_time(datetime.now(timezone.utc)) - logger.log_struct({"severity":"INFO","jsonPayload":result}) + logger.log_struct(result, "INFO") extract_api_time = time.time() - start_time logging.info(f"extraction completed in {extract_api_time:.2f} seconds for file name {file_name}") return create_api_response('Success', data=result, file_source= source_type) @@ -222,7 +222,7 @@ async def extract_knowledge_graph_from_file( logging.info(f'Deleted File Path: {merged_file_path} and Deleted File Name : {file_name}') delete_uploaded_local_file(merged_file_path,file_name) json_obj = {'message':message,'error_message':error_message, 'file_name': file_name,'status':'Failed','db_url':uri,'failed_count':1, 'source_type': source_type, 'source_url':source_url, 'wiki_query':wiki_query, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct({"severity":"ERROR","jsonPayload":json_obj}) + logger.log_struct(json_obj, "ERROR") logging.exception(f'File Failed in extraction: {json_obj}') return create_api_response('Failed', message=message + error_message[:100], error=error_message, file_name = file_name) finally: @@ -239,7 +239,7 @@ async def get_source_list(uri:str, userName:str, password:str, database:str=None uri = uri.replace(" ","+") result = await asyncio.to_thread(get_source_list_from_graph,uri,userName,decoded_password,database) json_obj = {'api_name':'sources_list','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct({"severity":"INFO","jsonPayload":json_obj}) + logger.log_struct(json_obj, "INFO") return create_api_response("Success",data=result) except Exception as e: job_status = "Failed" @@ -269,7 +269,7 @@ async def post_processing(uri=Form(), userName=Form(), password=Form(), database json_obj = {'api_name': 'post_processing/create_entity_embedding', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} logging.info(f'Entity Embeddings created') - logger.log_struct({"severity":"INFO","jsonPayload":json_obj}) + logger.log_struct(json_obj, "INFO") return create_api_response('Success', message='All tasks completed successfully') except Exception as e: @@ -298,7 +298,7 @@ async def chat_bot(uri=Form(),model=Form(None),userName=Form(), password=Form(), result["info"]["response_time"] = round(total_call_time, 2) json_obj = {'api_name':'chat_bot','db_url':uri,'session_id':session_id, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct({"severity":"INFO","jsonPayload":json_obj}) + logger.log_struct(json_obj, "INFO") return create_api_response('Success',data=result) except Exception as e: @@ -316,7 +316,7 @@ async def chunk_entities(uri=Form(),userName=Form(), password=Form(), chunk_ids= logging.info(f"URI: {uri}, Username: {userName}, chunk_ids: {chunk_ids}") result = await asyncio.to_thread(get_entities_from_chunkids,uri=uri, username=userName, password=password, chunk_ids=chunk_ids) json_obj = {'api_name':'chunk_entities','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct({"severity":"INFO","jsonPayload":json_obj}) + logger.log_struct(json_obj, "INFO") return create_api_response('Success',data=result) except Exception as e: job_status = "Failed" @@ -344,7 +344,7 @@ async def graph_query( document_names=document_names ) json_obj = {'api_name':'graph_query','db_url':uri,'document_names':document_names, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct({"severity":"INFO","jsonPayload":json_obj}) + logger.log_struct(json_obj, "INFO") return create_api_response('Success', data=result) except Exception as e: job_status = "Failed" @@ -377,7 +377,7 @@ async def connect(uri=Form(), userName=Form(), password=Form(), database=Form()) graph = create_graph_database_connection(uri, userName, password, database) result = await asyncio.to_thread(connection_check_and_get_vector_dimensions, graph) json_obj = {'api_name':'connect','db_url':uri,'status':result, 'count':1, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct({"severity":"INFO","jsonPayload":json_obj}) + logger.log_struct(json_obj, "INFO") return create_api_response('Success',data=result) except Exception as e: job_status = "Failed" @@ -394,7 +394,7 @@ async def upload_large_file_into_chunks(file:UploadFile = File(...), chunkNumber graph = create_graph_database_connection(uri, userName, password, database) result = await asyncio.to_thread(upload_file, graph, model, file, chunkNumber, totalChunks, originalname, uri, CHUNK_DIR, MERGED_DIR) json_obj = {'api_name':'upload','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct({"severity":"INFO","jsonPayload":json_obj}) + logger.log_struct(json_obj, "INFO") if int(chunkNumber) == int(totalChunks): return create_api_response('Success',data=result, message='Source Node Created Successfully') else: @@ -416,7 +416,7 @@ async def get_structured_schema(uri=Form(), userName=Form(), password=Form(), da result = await asyncio.to_thread(get_labels_and_relationtypes, graph) logging.info(f'Schema result from DB: {result}') json_obj = {'api_name':'schema','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct({"severity":"INFO","jsonPayload":json_obj}) + logger.log_struct(json_obj, "INFO") return create_api_response('Success', data=result) except Exception as e: message="Unable to get the labels and relationtypes from neo4j database" @@ -485,7 +485,7 @@ async def delete_document_and_entities(uri=Form(), # entities_count = result[0]['deletedEntities'] if 'deletedEntities' in result[0] else 0 message = f"Deleted {files_list_size} documents with entities from database" json_obj = {'api_name':'delete_document_and_entities','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct({"severity":"INFO","jsonPayload":json_obj}) + logger.log_struct(json_obj, "INFO") return create_api_response('Success',message=message) except Exception as e: job_status = "Failed" diff --git a/backend/src/logger.py b/backend/src/logger.py index ae26a764b..6a9822787 100644 --- a/backend/src/logger.py +++ b/backend/src/logger.py @@ -11,8 +11,8 @@ def __init__(self): else: self.logger = None - def log_struct(self, message): + def log_struct(self, message, severity="DEFAULT"): if self.is_gcp_log_enabled and message is not None: - self.logger.log_struct(message) + self.logger.log_struct({"message": message, "severity": severity}) else: - print(message) + print(f"[{severity}]{message}") From dd89e0b25e29c39df968339373d7d883eb78a54d Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Mon, 16 Sep 2024 15:45:59 +0000 Subject: [PATCH 091/292] community check --- frontend/src/components/Graph/GraphViewModal.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/Graph/GraphViewModal.tsx b/frontend/src/components/Graph/GraphViewModal.tsx index c29ae1c75..617d925a6 100644 --- a/frontend/src/components/Graph/GraphViewModal.tsx +++ b/frontend/src/components/Graph/GraphViewModal.tsx @@ -398,6 +398,8 @@ const GraphViewModal: React.FunctionComponent = ({ setRelationships(updatedRelations); setNodes(updatedNodes); }; + + // const isCommunity = allNodes.some(n=>n.labels.includes('__Community__')); return ( <> = ({ graphType={graphType} loading={loading} handleChange={handleCheckboxChange} - isgds={isGdsActive} + isgds={allNodes.some(n=>n.labels.includes('__Community__'))} /> )} From 6ed968d5936b6a81e831fc717dae92eeabb0bc09 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Tue, 17 Sep 2024 09:16:42 +0000 Subject: [PATCH 092/292] Entity Empty Label fix and Icon --- .../src/components/ChatBot/ChatInfoModal.tsx | 84 ++++++++++++------- .../src/components/Graph/GraphViewModal.tsx | 2 +- .../Deduplication/index.tsx | 4 +- frontend/src/utils/Utils.ts | 8 +- 4 files changed, 62 insertions(+), 36 deletions(-) diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index 2d4381f59..14b4f3bb8 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -57,7 +57,7 @@ const ChatInfoModal: React.FC = ({ }) => { const { breakpoints } = tokens; const isTablet = useMediaQuery(`(min-width:${breakpoints.xs}) and (max-width: ${breakpoints.lg})`); - const [activeTab, setActiveTab] = useState(error.length ? 10 : mode === 'graph' ? 4 : 3); + const [activeTab, setActiveTab] = useState(error?.length ? 10 : mode === 'graph' ? 4 : 3); const [infoEntities, setInfoEntities] = useState([]); const [communities, setCommunities] = useState([]); const [loading, setLoading] = useState(false); @@ -106,8 +106,30 @@ const ChatInfoModal: React.FC = ({ if (response.data.status === 'Failure') { throw new Error(response.data.error); } - setInfoEntities(response.data.data.nodes); - setNodes(response.data.data.nodes); + setInfoEntities( + response.data.data.nodes.map((n: Entity) => { + if (!n.labels.length && mode === 'entity search+vector') { + return { + ...n, + labels: ['Entity'], + }; + } + return n; + + }) + ); + setNodes( + response.data.data.nodes.map((n: ExtendedNode) => { + if (!n.labels.length && mode === 'entity search+vector') { + return { + ...n, + labels: ['Entity'], + }; + } + return n; + + }) + ); setRelationships(response.data.data.relationships); setCommunities(response.data.data.community_data); const chunks = response.data.data.chunk_data.map((chunk: any) => { @@ -132,15 +154,17 @@ const ChatInfoModal: React.FC = ({ }, [chunk_ids, mode, error]); const groupedEntities = useMemo<{ [key: string]: GroupedEntity }>(() => { - return infoEntities.reduce((acc, entity) => { + const items = infoEntities.reduce((acc, entity) => { const { label, text } = parseEntity(entity); if (!acc[label]) { + console.log({ label, text }); const newColor = calcWordColor(label); acc[label] = { texts: new Set(), color: newColor }; } acc[label].texts.add(text); return acc; }, {} as Record; color: string }>); + return items; }, [infoEntities]); const onChangeTabs = (tabId: number) => { @@ -149,7 +173,7 @@ const ChatInfoModal: React.FC = ({ const labelCounts = useMemo(() => { const counts: { [label: string]: number } = {}; - for (let index = 0; index < infoEntities.length; index++) { + for (let index = 0; index < infoEntities?.length; index++) { const entity = infoEntities[index]; const { labels } = entity; const [label] = labels; @@ -205,7 +229,7 @@ const ChatInfoModal: React.FC = ({ ) : ( <> )} - {mode === 'graph' && cypher_query?.trim().length ? ( + {mode === 'graph' && cypher_query?.trim()?.length ? ( Generated Cypher Query ) : ( <> @@ -219,10 +243,10 @@ const ChatInfoModal: React.FC = ({ - ) : mode === 'entity search+vector' && chunks.length ? ( + ) : mode === 'entity search+vector' && chunks?.length ? (
    {chunks - .map((c) => ({ fileName: c.fileName, fileSource: c.fileType })) + .map((c) => ({ fileName: c.fileName, fileSource: c.fileSource })) .map((s, index) => { return (
  • @@ -235,7 +259,6 @@ const ChatInfoModal: React.FC = ({ width={20} height={20} className='mr-2' - alt='S3 Logo' /> )} = ({ ); })}
- ) : sources.length ? ( + ) : sources?.length ? (
    {sources.map((link, index) => { return ( @@ -351,7 +374,7 @@ const ChatInfoModal: React.FC = ({ - ) : Object.keys(groupedEntities).length > 0 || Object.keys(graphonly_entities).length > 0 ? ( + ) : Object.keys(groupedEntities)?.length > 0 || Object.keys(graphonly_entities)?.length > 0 ? (
      {mode == 'graph' ? graphonly_entities.map((label, index) => ( @@ -367,26 +390,25 @@ const ChatInfoModal: React.FC = ({
)) - : sortedLabels.map((label, index) => ( -
  • -
    { + const entity = groupedEntities[label == 'undefined' ? 'Entity' : label]; + return ( +
  • - {label} ({labelCounts[label]}) - - - {Array.from(groupedEntities[label].texts).slice(0, 3).join(', ')} - -
  • - ))} +
    + {label} ({labelCounts[label]}) +
    + + {Array.from(entity.texts).slice(0, 3).join(', ')} + + + ); + })} ) : ( No Entities Found @@ -397,7 +419,7 @@ const ChatInfoModal: React.FC = ({ - ) : chunks.length > 0 ? ( + ) : chunks?.length > 0 ? (
      {chunks.map((chunk) => ( @@ -522,7 +544,7 @@ const ChatInfoModal: React.FC = ({ <> )} - {activeTab == 4 && nodes.length && relationships.length ? ( + {activeTab == 4 && nodes?.length && relationships?.length ? ( diff --git a/frontend/src/components/Graph/GraphViewModal.tsx b/frontend/src/components/Graph/GraphViewModal.tsx index 617d925a6..50c381685 100644 --- a/frontend/src/components/Graph/GraphViewModal.tsx +++ b/frontend/src/components/Graph/GraphViewModal.tsx @@ -421,7 +421,7 @@ const GraphViewModal: React.FunctionComponent = ({ graphType={graphType} loading={loading} handleChange={handleCheckboxChange} - isgds={allNodes.some(n=>n.labels.includes('__Community__'))} + isgds={allNodes.some((n) => n.labels.includes('__Community__'))} /> )} diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx index 36fcff3d1..f5a021e30 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx @@ -80,12 +80,12 @@ export default function DeduplicationTab() { const onRemove = (nodeid: string, similarNodeId: string) => { setDuplicateNodes((prev) => { return prev.map((d) => - d.e.elementId === nodeid + (d.e.elementId === nodeid ? { ...d, similar: d.similar.filter((n) => n.elementId != similarNodeId), } - : d + : d) ); }); }; diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index 3eb5f7ab7..88aabd01c 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -359,8 +359,11 @@ export const capitalize = (word: string): string => { }; export const parseEntity = (entity: Entity) => { const { labels, properties } = entity; - const [label] = labels; + let [label] = labels; const text = properties.id; + if (!label) { + label = 'Entity'; + } return { label, text }; }; @@ -392,7 +395,7 @@ export const isFileCompleted = (waitingFile: CustomFile, item: SourceNode) => waitingFile && item.status === 'Completed'; export const calculateProcessedCount = (prev: number, batchSize: number) => - prev === batchSize ? batchSize - 1 : prev + 1; + (prev === batchSize ? batchSize - 1 : prev + 1); export const isProcessingFileValid = (item: SourceNode, userCredentials: UserCredentials) => { return item.status === 'Processing' && item.fileName != undefined && userCredentials && userCredentials.database; @@ -429,6 +432,7 @@ export const getDescriptionForChatMode = (mode: string): string => { } }; export const getLogo = (mode: string): Record => { + console.log(mode); if (mode === 'light') { return { Wikipedia: Wikipediadarkmode, From 9237847b7880a900fab123fdf76be2e6d6f1499c Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Tue, 17 Sep 2024 15:15:52 +0530 Subject: [PATCH 093/292] Update Utils.ts --- frontend/src/utils/Utils.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index 88aabd01c..b59c082fd 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -432,7 +432,6 @@ export const getDescriptionForChatMode = (mode: string): string => { } }; export const getLogo = (mode: string): Record => { - console.log(mode); if (mode === 'light') { return { Wikipedia: Wikipediadarkmode, From 5f2290bf9b59d4f98c3555eea2b8bcbed6c955ec Mon Sep 17 00:00:00 2001 From: aashipandya <156318202+aashipandya@users.noreply.github.com> Date: Tue, 17 Sep 2024 16:30:24 +0530 Subject: [PATCH 094/292] Retry processing - node and rels count update condition for start from beginning (#737) * Remove TotalPages when save file on local (#684) * file_name reference and verify_ssl issue fixed (#683) * User flow changes for recreating supported vector index (#682) * removed the if check * Add one more check for create vector index when chunks are exist without embeddings * removed local files * condition changes * chunks exists check * chunk exists without embeddings check * vector Index issue fixed * vector index with different dimension * Update graphDB_dataAccess.py --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Remove TotalPages when save file on local (#684) * file_name reference and verify_ssl issue fixed (#683) * User flow changes for recreating supported vector index (#682) * removed the if check * Add one more check for create vector index when chunks are exist without embeddings * removed local files * condition changes * chunks exists check * chunk exists without embeddings check * vector Index issue fixed * vector index with different dimension * Update graphDB_dataAccess.py --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Reapply "Dockerfile changes with VITE label" This reverts commit a83e0855fbf54d2b5af009d96c4edf0bcd7ab84a. * Revert "Dockerfile changes with VITE label" This reverts commit 2840ebc9e6156c51465a9f54be72ca2d014147c2. * Concurrent processing of files (#665) * Update README.md * Droped the old vector index (#652) * added cypher_queries and llm chatbot files * updated llm-chatbot-python * added llm-chatbot-python * updated llm-chatbot-python folder * Added chatbot "hybrid " mode use case * added the concurrent file processing * page refresh scenario * fixed waiting files processing issue in refresh scenario * removed boolean param * fixed processedCount issue * checkbox with waiting check * fixed the refresh scenario with processing files * processing files check * server side error * processing file count check for processing files less than batch size * processing count check to handle allselected files * created helper functions * code improvements * __ changes (#656) * DiffbotGraphTransformer doesn't need an LLMGraphTransformer (#659) Co-authored-by: jeromechoo * Removed experiments/llm-chatbot-python folder from DEV branch * redcued the password clear timeout * Removed experiments/Cypher_Queries.ipynb file from DEV branch * disabled the closed button on banner and connection dialog while API is in pending state * update delete query with entities * node id check (#663) * Status source and type filtering (#664) * status source * Name change * type change * rollback to previous working nvl version * added the alert * add BATCH_SIZE to docker * temp fixes for 0.3.1 * alert fix for less than batch size processing * new virtual env * added Hybrid Chat modes (#670) * Rename the function #657 * label and checkboxes placement changes (#675) * label and checkboxes placement changes * checkbox placement changes * Graph node filename check * env fixes with latest nvl libraries * format fixes * removed local files * Remove TotalPages when save file on local (#684) * file_name reference and verify_ssl issue fixed (#683) * User flow changes for recreating supported vector index (#682) * removed the if check * Add one more check for create vector index when chunks are exist without embeddings * removed local files * condition changes * chunks exists check * chunk exists without embeddings check * vector Index issue fixed * vector index with different dimension * Update graphDB_dataAccess.py --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * ndl changes * label and checkboxes placement changes (#675) * label and checkboxes placement changes * checkbox placement changes * env fixes with latest nvl libraries * format fixes * User flow changes for recreating supported vector index (#682) * removed the if check * Add one more check for create vector index when chunks are exist without embeddings * removed local files * condition changes * chunks exists check * chunk exists without embeddings check * vector Index issue fixed * vector index with different dimension * Update graphDB_dataAccess.py --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * env fixes with latest nvl libraries * format fixes * User flow changes for recreating supported vector index (#682) * removed the if check * Add one more check for create vector index when chunks are exist without embeddings * removed local files * condition changes * chunks exists check * chunk exists without embeddings check * vector Index issue fixed * vector index with different dimension * Update graphDB_dataAccess.py --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Status source and type filtering (#664) * status source * Name change * type change * added the alert * temp fixes for 0.3.1 * label and checkboxes placement changes (#675) * label and checkboxes placement changes * checkbox placement changes * env fixes with latest nvl libraries * format fixes * User flow changes for recreating supported vector index (#682) * removed the if check * Add one more check for create vector index when chunks are exist without embeddings * removed local files * condition changes * chunks exists check * chunk exists without embeddings check * vector Index issue fixed * vector index with different dimension * Update graphDB_dataAccess.py --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * ndl changes * env fixes with latest nvl libraries * format fixes * User flow changes for recreating supported vector index (#682) * removed the if check * Add one more check for create vector index when chunks are exist without embeddings * removed local files * condition changes * chunks exists check * chunk exists without embeddings check * vector Index issue fixed * vector index with different dimension * Update graphDB_dataAccess.py --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * env fixes with latest nvl libraries * format fixes * User flow changes for recreating supported vector index (#682) * removed the if check * Add one more check for create vector index when chunks are exist without embeddings * removed local files * condition changes * chunks exists check * chunk exists without embeddings check * vector Index issue fixed * vector index with different dimension * Update graphDB_dataAccess.py --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * added cypher_queries and llm chatbot files * updated llm-chatbot-python * added llm-chatbot-python * updated llm-chatbot-python folder * page refresh scenario * fixed waiting files processing issue in refresh scenario * Removed experiments/llm-chatbot-python folder from DEV branch * disabled the closed button on banner and connection dialog while API is in pending state * node id check (#663) * Status source and type filtering (#664) * status source * Name change * type change * rollback to previous working nvl version * added the alert * temp fixes for 0.3.1 * label and checkboxes placement changes (#675) * label and checkboxes placement changes * checkbox placement changes * env fixes with latest nvl libraries * format fixes * User flow changes for recreating supported vector index (#682) * removed the if check * Add one more check for create vector index when chunks are exist without embeddings * removed local files * condition changes * chunks exists check * chunk exists without embeddings check * vector Index issue fixed * vector index with different dimension * Update graphDB_dataAccess.py --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * ndl changes * env fixes with latest nvl libraries * format fixes * User flow changes for recreating supported vector index (#682) * removed the if check * Add one more check for create vector index when chunks are exist without embeddings * removed local files * condition changes * chunks exists check * chunk exists without embeddings check * vector Index issue fixed * vector index with different dimension * Update graphDB_dataAccess.py --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * env fixes with latest nvl libraries * format fixes * User flow changes for recreating supported vector index (#682) * removed the if check * Add one more check for create vector index when chunks are exist without embeddings * removed local files * condition changes * chunks exists check * chunk exists without embeddings check * vector Index issue fixed * vector index with different dimension * Update graphDB_dataAccess.py --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Status source and type filtering (#664) * status source * Name change * type change * added the alert * temp fixes for 0.3.1 * label and checkboxes placement changes (#675) * label and checkboxes placement changes * checkbox placement changes * env fixes with latest nvl libraries * format fixes * User flow changes for recreating supported vector index (#682) * removed the if check * Add one more check for create vector index when chunks are exist without embeddings * removed local files * condition changes * chunks exists check * chunk exists without embeddings check * vector Index issue fixed * vector index with different dimension * Update graphDB_dataAccess.py --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * ndl changes * env fixes with latest nvl libraries * format fixes * User flow changes for recreating supported vector index (#682) * removed the if check * Add one more check for create vector index when chunks are exist without embeddings * removed local files * condition changes * chunks exists check * chunk exists without embeddings check * vector Index issue fixed * vector index with different dimension * Update graphDB_dataAccess.py --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * env fixes with latest nvl libraries * format fixes * User flow changes for recreating supported vector index (#682) * removed the if check * Add one more check for create vector index when chunks are exist without embeddings * removed local files * condition changes * chunks exists check * chunk exists without embeddings check * vector Index issue fixed * vector index with different dimension * Update graphDB_dataAccess.py --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * property spell fix --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Jayanth T Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Jerome Choo Co-authored-by: jeromechoo Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * env changes * format fixes * set retry status * retry processing backend * added the retry icon on rows * vite changes in docker compose * added retry dialog * Integrated the Retry processing API * Integrated the Extract API fro retry processing * Integrated ndl toast component * replaced foreach with normal for loop for better performance * types improvements * used toast component * spell fix * Issue fixed * processing changes in main * function closing fix * retry processing issue fixed * autoclosing the retry popup on retry api success * removed the retry if check * resetting the node and relationship count on retry * added the enter key events on the popups * fixed wikipedia icon on large file alert popup * setting nodes to 0 and start from last processed chunk logic changes * Retry Popup fixes * status changes for upload failed scenario * kept condition specific * changed status to reprocess from retry * Reprocess wording changes * tooltip changes * wordings and size changes * Changed status to Reprocess * updated node count for start from begnning --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Jayanth T Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: Jerome Choo Co-authored-by: jeromechoo --- backend/src/main.py | 12 +++++++++--- backend/src/shared/constants.py | 7 ++++++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/backend/src/main.py b/backend/src/main.py index cc5569c0d..eebdff70f 100644 --- a/backend/src/main.py +++ b/backend/src/main.py @@ -5,7 +5,8 @@ QUERY_TO_GET_LAST_PROCESSED_CHUNK_WITHOUT_ENTITY, START_FROM_BEGINNING, START_FROM_LAST_PROCESSED_POSITION, - DELETE_ENTITIES_AND_START_FROM_BEGINNING) + DELETE_ENTITIES_AND_START_FROM_BEGINNING, + QUERY_TO_GET_NODES_AND_RELATIONS_OF_A_DOCUMENT) from src.shared.schema_extraction import schema_extraction_from_text from langchain_community.document_loaders import GoogleApiClient, GoogleApiYoutubeLoader from dotenv import load_dotenv @@ -342,8 +343,13 @@ def processing_source(uri, userName, password, database, model, file_name, pages obj_source_node.updated_at = end_time obj_source_node.processing_time = processed_time obj_source_node.processed_chunk = select_chunks_upto+select_chunks_with_retry - obj_source_node.node_count = node_count - obj_source_node.relationship_count = rel_count + if retry_condition == START_FROM_BEGINNING: + result = graph.query(QUERY_TO_GET_NODES_AND_RELATIONS_OF_A_DOCUMENT, params={"filename":file_name}) + obj_source_node.node_count = result[0]['nodes'] + obj_source_node.relationship_count = result[0]['rels'] + else: + obj_source_node.node_count = node_count + obj_source_node.relationship_count = rel_count graphDb_data_Access.update_source_node(obj_source_node) result = graphDb_data_Access.get_current_status_document_node(file_name) diff --git a/backend/src/shared/constants.py b/backend/src/shared/constants.py index 8bb1c56b1..c6d404a7f 100644 --- a/backend/src/shared/constants.py +++ b/backend/src/shared/constants.py @@ -312,7 +312,12 @@ RETURN c.id as id,c.position as position ORDER BY c.position LIMIT 1 """ - +QUERY_TO_GET_NODES_AND_RELATIONS_OF_A_DOCUMENT = """ + MATCH (d:Document)<-[:PART_OF]-(:Chunk)-[:HAS_ENTITY]->(e) where d.fileName=$filename + OPTIONAL MATCH (d)<-[:PART_OF]-(:Chunk)-[:HAS_ENTITY]->(e2:!Chunk)-[rel]-(e) + RETURN count(DISTINCT e) as nodes, count(DISTINCT rel) as rels + """ + START_FROM_BEGINNING = "start_from_beginning" DELETE_ENTITIES_AND_START_FROM_BEGINNING = "delete_entities_and_start_from_beginning" START_FROM_LAST_PROCESSED_POSITION = "start_from_last_processed_position" From fec0d1ec38319e18ba27f0440a4f57c8a4f80316 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Tue, 17 Sep 2024 11:06:06 +0000 Subject: [PATCH 095/292] uncommented the Retry Processing --- frontend/src/components/FileTable.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/FileTable.tsx b/frontend/src/components/FileTable.tsx index f6a0c0c08..aa4d9bb9a 100644 --- a/frontend/src/components/FileTable.tsx +++ b/frontend/src/components/FileTable.tsx @@ -35,7 +35,7 @@ import { } from '../utils/Utils'; import { SourceNode, CustomFile, FileTableProps, UserCredentials, statusupdate, ChildRef } from '../types'; import { useCredentials } from '../context/UserCredentials'; -import {MagnifyingGlassCircleIconSolid } from '@neo4j-ndl/react/icons'; +import { ArrowPathIconSolid, MagnifyingGlassCircleIconSolid } from '@neo4j-ndl/react/icons'; import CustomProgressBar from './UI/CustomProgressBar'; import subscribe from '../services/PollingAPI'; import { triggerStatusUpdateAPI } from '../services/ServerSideStatusUpdateAPI'; @@ -49,7 +49,7 @@ import IndeterminateCheckbox from './UI/CustomCheckBox'; import { showErrorToast, showNormalToast } from '../utils/toasts'; let onlyfortheFirstRender = true; const FileTable = forwardRef((props, ref) => { - const { isExpanded, connectionStatus, setConnectionStatus, onInspect } = props; + const { isExpanded, connectionStatus, setConnectionStatus, onInspect, onRetry } = props; const { filesData, setFilesData, model, rowSelection, setRowSelection, setSelectedRows, setProcessedCount, queue } = useFileContext(); const { userCredentials } = useCredentials(); @@ -146,7 +146,7 @@ const FileTable = forwardRef((props, ref) => { > {info.getValue()} - {/* {(info.getValue() === 'Completed' || + {(info.getValue() === 'Completed' || info.getValue() === 'Failed' || info.getValue() === 'Cancelled') && ( @@ -161,7 +161,7 @@ const FileTable = forwardRef((props, ref) => { - )} */} + )}
    ); } else if (info.getValue() === 'Processing' && info.row.original.processingProgress === undefined) { From dff7535b1001233e0a0b62a2162f36f45930657f Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Tue, 17 Sep 2024 11:30:01 +0000 Subject: [PATCH 096/292] removed __Entity__ labels --- backend/src/chunkid_entities.py | 8 ++++++++ backend/src/shared/constants.py | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/backend/src/chunkid_entities.py b/backend/src/chunkid_entities.py index 30b1c15a9..53a0544f6 100644 --- a/backend/src/chunkid_entities.py +++ b/backend/src/chunkid_entities.py @@ -19,10 +19,18 @@ def process_records(records): relationship = element['relationship'] if start_node['element_id'] not in seen_nodes: + if "labels" in start_node.keys(): + labels = set(start_node["labels"]) + labels.discard("__Entity__") + start_node["labels"] = list(labels) nodes.append(start_node) seen_nodes.add(start_node['element_id']) if end_node['element_id'] not in seen_nodes: + if "labels" in end_node.keys(): + labels = set(end_node["labels"]) + labels.discard("__Entity__") + end_node["labels"] = list(labels) nodes.append(end_node) seen_nodes.add(end_node['element_id']) diff --git a/backend/src/shared/constants.py b/backend/src/shared/constants.py index 4ec88e8a5..8a1d2bba2 100644 --- a/backend/src/shared/constants.py +++ b/backend/src/shared/constants.py @@ -74,7 +74,7 @@ MATCH (chunk)-[:PART_OF]->(d:Document) CALL {WITH chunk MATCH (chunk)-[:HAS_ENTITY]->(e) -MATCH path=(e)(()-[rels:!HAS_ENTITY&!PART_OF]-()){0,2}(:!Chunk &! Document) +MATCH path=(e)(()-[rels:!HAS_ENTITY&!PART_OF]-()){0,2}(:!Chunk &! Document &! `__Community__`) UNWIND rels as r RETURN collect(distinct r) as rels } From e3bcf2be1a29d36b00162019c028f875e660aca8 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Tue, 17 Sep 2024 12:09:48 +0000 Subject: [PATCH 097/292] spell fix --- frontend/src/services/CommonAPI.ts | 2 +- frontend/src/types.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/services/CommonAPI.ts b/frontend/src/services/CommonAPI.ts index b55d002fe..d1d5c767b 100644 --- a/frontend/src/services/CommonAPI.ts +++ b/frontend/src/services/CommonAPI.ts @@ -1,5 +1,5 @@ import { AxiosResponse, Method } from 'axios'; -import { UserCredentials, FormDataParams } from '../types'; +import { UserCredentials, FormDataParams } from '../types'; import api from '../API/Index'; // API Call diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 8b00b1695..679756dd9 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -84,7 +84,7 @@ export type UploadParams = { originalname: string; } & { [key: string]: any }; -export type ForDataParams = ExtractParams | UploadParams; +export type FormDataParams = ExtractParams | UploadParams; export interface DropdownProps { onSelect: (option: OptionType | null | void) => void; From a86dd12e903c855a502bfd266ac7657f854e6fbf Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Wed, 18 Sep 2024 06:52:12 +0000 Subject: [PATCH 098/292] fixed postprocessing method invoking issue for odd no files --- frontend/src/components/ChatBot/ChatInfoModal.tsx | 10 ++++------ frontend/src/components/Content.tsx | 7 +++++-- frontend/src/services/CommonAPI.ts | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index 14b4f3bb8..758d793da 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -113,9 +113,8 @@ const ChatInfoModal: React.FC = ({ ...n, labels: ['Entity'], }; - } - return n; - + } + return n; }) ); setNodes( @@ -125,9 +124,8 @@ const ChatInfoModal: React.FC = ({ ...n, labels: ['Entity'], }; - } - return n; - + } + return n; }) ); setRelationships(response.data.data.relationships); diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 5862abe05..fb11e3fa0 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -145,7 +145,10 @@ const Content: React.FC = ({ if (processedCount == batchSize) { handleGenerateGraph([], true); } - }, [processedCount, userCredentials]); + if (processedCount === 1 && queue.isEmpty()) { + (async () => await postProcessing(userCredentials as UserCredentials, postProcessingTasks))(); + } + }, [processedCount, userCredentials, queue]); useEffect(() => { if (afterFirstRender) { @@ -363,7 +366,7 @@ const Content: React.FC = ({ const addFilesToQueue = async (remainingFiles: CustomFile[]) => { if (!remainingFiles.length) { - await postProcessing(userCredentials as UserCredentials, postProcessingTasks); + (async () => await postProcessing(userCredentials as UserCredentials, postProcessingTasks))(); } for (let index = 0; index < remainingFiles.length; index++) { const f = remainingFiles[index]; diff --git a/frontend/src/services/CommonAPI.ts b/frontend/src/services/CommonAPI.ts index d1d5c767b..b55d002fe 100644 --- a/frontend/src/services/CommonAPI.ts +++ b/frontend/src/services/CommonAPI.ts @@ -1,5 +1,5 @@ import { AxiosResponse, Method } from 'axios'; -import { UserCredentials, FormDataParams } from '../types'; +import { UserCredentials, FormDataParams } from '../types'; import api from '../API/Index'; // API Call From ba0957efc3265116c3dbad9683ffee2bd5d2b828 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Wed, 18 Sep 2024 06:57:26 +0000 Subject: [PATCH 099/292] lint fix --- frontend/src/components/Content.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index fb11e3fa0..f76e45cb4 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -146,7 +146,9 @@ const Content: React.FC = ({ handleGenerateGraph([], true); } if (processedCount === 1 && queue.isEmpty()) { - (async () => await postProcessing(userCredentials as UserCredentials, postProcessingTasks))(); + (async () => { + await postProcessing(userCredentials as UserCredentials, postProcessingTasks); + })(); } }, [processedCount, userCredentials, queue]); @@ -366,7 +368,7 @@ const Content: React.FC = ({ const addFilesToQueue = async (remainingFiles: CustomFile[]) => { if (!remainingFiles.length) { - (async () => await postProcessing(userCredentials as UserCredentials, postProcessingTasks))(); + await postProcessing(userCredentials as UserCredentials, postProcessingTasks); } for (let index = 0; index < remainingFiles.length; index++) { const f = remainingFiles[index]; From 3fecf70e5f6139e0631299358fe3c025a23ba365 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Wed, 18 Sep 2024 07:25:36 +0000 Subject: [PATCH 100/292] Added filesource and name in chunks --- .../src/components/ChatBot/ChatInfoModal.tsx | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index 758d793da..192b37407 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -489,14 +489,31 @@ const ChatInfoModal: React.FC = ({ Similarity Score: {chunk?.score} - ) : chunk.fileSource === 'local file' ? ( + ) : ( <> - Similarity Score: {chunk?.score} +
    + {chunk.fileSource === 'local file' ? ( + + ) : ( + + )} + + {chunk.fileName} + +
    - ) : ( - <> )} - {chunk?.text} + + Text: {chunk?.text} + ))} From 57550b787b2e8a1b56715169e8b6a46ac02d319e Mon Sep 17 00:00:00 2001 From: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Date: Wed, 18 Sep 2024 12:03:15 +0000 Subject: [PATCH 101/292] Preload=True remove from HSTS --- backend/score.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/score.py b/backend/score.py index bd1be1ea7..cecc42778 100644 --- a/backend/score.py +++ b/backend/score.py @@ -48,7 +48,7 @@ def sick(): app = FastAPI() SecWeb(app=app, Option={'referrer': False, 'xframe': False}) -app.add_middleware(HSTS, Option={'max-age': 4, 'preload': True}) +app.add_middleware(HSTS, Option={'max-age': 4}) app.add_middleware(ContentSecurityPolicy, Option={'default-src': ["'self'"], 'base-uri': ["'self'"], 'block-all-mixed-content': []}, script_nonce=False, style_nonce=False, report_only=False) app.add_middleware(XContentTypeOptions) app.add_middleware(XFrame, Option={'X-Frame-Options': 'DENY'}) From 1695f19c8802c7d26e0aacd3793595f8ada5c884 Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Wed, 18 Sep 2024 18:41:07 +0530 Subject: [PATCH 102/292] Graph communities (#748) * UI changes * modes enable disable * separated sources entities chunk communities * communities added into separate component * Update ChatInfoModal.tsx * added filename and source for chunksinfo * removed the console.log * mode disable changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> --- backend/src/chunkid_entities.py | 3 + frontend/src/App.css | 2 +- .../src/components/ChatBot/ChatInfoModal.tsx | 413 ++---------------- .../src/components/ChatBot/ChatModeToggle.tsx | 64 +-- frontend/src/components/ChatBot/ChunkInfo.tsx | 127 ++++++ .../src/components/ChatBot/Communities.tsx | 36 ++ .../src/components/ChatBot/EntitiesInfo.tsx | 91 ++++ .../src/components/ChatBot/SourcesInfo.tsx | 139 ++++++ frontend/src/types.ts | 24 + frontend/src/utils/Utils.ts | 11 + 10 files changed, 508 insertions(+), 402 deletions(-) create mode 100644 frontend/src/components/ChatBot/ChunkInfo.tsx create mode 100644 frontend/src/components/ChatBot/Communities.tsx create mode 100644 frontend/src/components/ChatBot/EntitiesInfo.tsx create mode 100644 frontend/src/components/ChatBot/SourcesInfo.tsx diff --git a/backend/src/chunkid_entities.py b/backend/src/chunkid_entities.py index 53a0544f6..3fd3c3a71 100644 --- a/backend/src/chunkid_entities.py +++ b/backend/src/chunkid_entities.py @@ -135,6 +135,9 @@ def process_entityids(driver, chunk_ids): logging.info(f"Nodes and relationships are processed") result["chunk_data"] = records[0]["chunks"] result["community_data"] = records[0]["communities"] + else: + result["chunk_data"] = list() + result["community_data"] = list() logging.info(f"Query process completed successfully for chunk ids: {chunk_ids}") return result except Exception as e: diff --git a/frontend/src/App.css b/frontend/src/App.css index 615b8559b..e912a05e2 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -385,5 +385,5 @@ .custom-menu { min-width: 250px; - max-width: 300px; + max-width: 305px; } \ No newline at end of file diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index 192b37407..82fa25e26 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -1,48 +1,36 @@ import { Box, Typography, - TextLink, Flex, Tabs, - LoadingSpinner, CypherCodeBlock, CypherCodeBlockProps, useCopyToClipboard, Banner, useMediaQuery, } from '@neo4j-ndl/react'; -import { - DocumentDuplicateIconOutline, - DocumentTextIconOutline, - ClipboardDocumentCheckIconOutline, - GlobeAltIconOutline, -} from '@neo4j-ndl/react/icons'; +import { DocumentDuplicateIconOutline, ClipboardDocumentCheckIconOutline } from '@neo4j-ndl/react/icons'; import '../../styling/info.css'; import Neo4jRetrievalLogo from '../../assets/images/Neo4jRetrievalLogo.png'; -import wikipedialogo from '../../assets/images/wikipedia.svg'; -import youtubelogo from '../../assets/images/youtube.svg'; -import gcslogo from '../../assets/images/gcs.webp'; -import s3logo from '../../assets/images/s3logo.png'; import { Chunk, Community, Entity, ExtendedNode, ExtendedRelationship, - GroupedEntity, UserCredentials, chatInfoMessage, } from '../../types'; import { useContext, useEffect, useMemo, useState } from 'react'; -import HoverableLink from '../UI/HoverableLink'; import GraphViewButton from '../Graph/GraphViewButton'; import { chunkEntitiesAPI } from '../../services/ChunkEntitiesInfo'; import { useCredentials } from '../../context/UserCredentials'; -import { calcWordColor } from '@neo4j-devtools/word-color'; -import ReactMarkdown from 'react-markdown'; -import { getLogo, parseEntity, youtubeLinkValidation } from '../../utils/Utils'; import { ThemeWrapperContext } from '../../context/ThemeWrapper'; import { tokens } from '@neo4j-ndl/base'; +import ChunkInfo from './ChunkInfo'; +import EntitiesInfo from './EntitiesInfo'; +import SourcesInfo from './SourcesInfo'; +import CommunitiesInfo from './Communities'; const ChatInfoModal: React.FC = ({ sources, @@ -106,8 +94,13 @@ const ChatInfoModal: React.FC = ({ if (response.data.status === 'Failure') { throw new Error(response.data.error); } + const nodesData = response?.data?.data?.nodes; + const relationshipsData = response?.data?.data?.relationships; + const communitiesData = response?.data?.data?.community_data; + const chunksData = response?.data?.data?.chunk_data; + setInfoEntities( - response.data.data.nodes.map((n: Entity) => { + nodesData.map((n: Entity) => { if (!n.labels.length && mode === 'entity search+vector') { return { ...n, @@ -118,30 +111,34 @@ const ChatInfoModal: React.FC = ({ }) ); setNodes( - response.data.data.nodes.map((n: ExtendedNode) => { + nodesData.map((n: ExtendedNode) => { if (!n.labels.length && mode === 'entity search+vector') { return { ...n, labels: ['Entity'], }; } - return n; + return n ?? []; }) ); - setRelationships(response.data.data.relationships); - setCommunities(response.data.data.community_data); - const chunks = response.data.data.chunk_data.map((chunk: any) => { - const chunkScore = chunk_ids.find((chunkdetail) => chunkdetail.id === chunk.id); - return { - ...chunk, - score: chunkScore?.score, - }; - }); - const sortedchunks = chunks.sort((a: any, b: any) => b.score - a.score); - setChunks(sortedchunks); + setRelationships(relationshipsData ?? []); + setCommunities(communitiesData ?? []); + setChunks( + chunksData + .map((chunk: any) => { + const chunkScore = chunk_ids.find((chunkdetail) => chunkdetail.id === chunk.id); + return ( + { + ...chunk, + score: chunkScore?.score, + } ?? [] + ); + }) + .sort((a: any, b: any) => b.score - a.score) + ); setLoading(false); } catch (error) { - console.error('Error fetching entities:', error); + console.error('Error fetching information:', error); setLoading(false); } })(); @@ -151,50 +148,10 @@ const ChatInfoModal: React.FC = ({ }; }, [chunk_ids, mode, error]); - const groupedEntities = useMemo<{ [key: string]: GroupedEntity }>(() => { - const items = infoEntities.reduce((acc, entity) => { - const { label, text } = parseEntity(entity); - if (!acc[label]) { - console.log({ label, text }); - const newColor = calcWordColor(label); - acc[label] = { texts: new Set(), color: newColor }; - } - acc[label].texts.add(text); - return acc; - }, {} as Record; color: string }>); - return items; - }, [infoEntities]); - const onChangeTabs = (tabId: number) => { setActiveTab(tabId); }; - const labelCounts = useMemo(() => { - const counts: { [label: string]: number } = {}; - for (let index = 0; index < infoEntities?.length; index++) { - const entity = infoEntities[index]; - const { labels } = entity; - const [label] = labels; - counts[label] = counts[label] ? counts[label] + 1 : 1; - } - return counts; - }, [infoEntities]); - - const sortedLabels = useMemo(() => { - return Object.keys(labelCounts).sort((a, b) => labelCounts[b] - labelCounts[a]); - }, [labelCounts]); - - const generateYouTubeLink = (url: string, startTime: string) => { - try { - const urlObj = new URL(url); - urlObj.searchParams.set('t', startTime); - return urlObj.toString(); - } catch (error) { - console.error('Invalid URL:', error); - return ''; - } - }; - return ( @@ -237,290 +194,18 @@ const ChatInfoModal: React.FC = ({ )} - {loading ? ( - - - - ) : mode === 'entity search+vector' && chunks?.length ? ( -
      - {chunks - .map((c) => ({ fileName: c.fileName, fileSource: c.fileSource })) - .map((s, index) => { - return ( -
    • -
      - {s.fileSource === 'local file' ? ( - - ) : ( - - )} - - {s.fileName} - -
      -
    • - ); - })} -
    - ) : sources?.length ? ( -
      - {sources.map((link, index) => { - return ( -
    • - {link?.startsWith('http') || link?.startsWith('https') ? ( - <> - {link?.includes('wikipedia.org') && ( -
      - Wikipedia Logo - - - - {link} - - - -
      - )} - {link?.includes('storage.googleapis.com') && ( -
      - Google Cloud Storage Logo - - {decodeURIComponent(link).split('/').at(-1)?.split('?')[0] ?? 'GCS File'} - -
      - )} - {youtubeLinkValidation(link) && ( - <> -
      - - - - - {link} - - - -
      - - )} - {!link?.startsWith('s3://') && - !link?.includes('storage.googleapis.com') && - !link?.includes('wikipedia.org') && - !link?.includes('youtube.com') && ( -
      - - - {link} - -
      - )} - - ) : link?.startsWith('s3://') ? ( -
      - S3 Logo - - {decodeURIComponent(link).split('/').at(-1) ?? 'S3 File'} - -
      - ) : ( -
      - - - {link} - -
      - )} -
    • - ); - })} -
    - ) : ( - No Sources Found - )} +
    - {loading ? ( - - - - ) : Object.keys(groupedEntities)?.length > 0 || Object.keys(graphonly_entities)?.length > 0 ? ( -
      - {mode == 'graph' - ? graphonly_entities.map((label, index) => ( -
    • -
      - { - // @ts-ignore - label[Object.keys(label)[0]].id ?? Object.keys(label)[0] - } -
      -
    • - )) - : sortedLabels.map((label, index) => { - const entity = groupedEntities[label == 'undefined' ? 'Entity' : label]; - return ( -
    • -
      - {label} ({labelCounts[label]}) -
      - - {Array.from(entity.texts).slice(0, 3).join(', ')} - -
    • - ); - })} -
    - ) : ( - No Entities Found - )} +
    - {loading ? ( - - - - ) : chunks?.length > 0 ? ( -
    -
      - {chunks.map((chunk) => ( -
    • - {chunk?.page_number ? ( - <> -
      - - - {/* {chunk?.fileName}, Page: {chunk?.page_number} */} - {chunk?.fileName} - -
      - Similarity Score: {chunk?.score} - - ) : chunk?.url && chunk?.start_time ? ( - <> -
      - - - - {chunk?.fileName} - - -
      - Similarity Score: {chunk?.score} - - ) : chunk?.url && chunk?.url.includes('wikipedia.org') ? ( - <> -
      - - {chunk?.fileName} -
      - Similarity Score: {chunk?.score} - - ) : chunk?.url && chunk?.url.includes('storage.googleapis.com') ? ( - <> -
      - - {chunk?.fileName} -
      - Similarity Score: {chunk?.score} - - ) : chunk?.url && chunk?.url.startsWith('s3://') ? ( - <> -
      - - {chunk?.fileName} -
      - Similarity Score: {chunk?.score} - - ) : chunk?.url && - !chunk?.url.startsWith('s3://') && - !chunk?.url.includes('storage.googleapis.com') && - !chunk?.url.includes('wikipedia.org') && - !chunk?.url.includes('youtube.com') ? ( - <> -
      - - - {chunk?.url} - -
      - Similarity Score: {chunk?.score} - - ) : ( - <> -
      - {chunk.fileSource === 'local file' ? ( - - ) : ( - - )} - - {chunk.fileName} - -
      - - )} - - Text: {chunk?.text} - -
    • - ))} -
    -
    - ) : ( - No Chunks Found - )} +
    = ({ /> {mode === 'entity search+vector' ? ( - - {loading ? ( - - - - ) : ( -
    -
      - {communities.map((community, index) => ( -
    • -
      - - ID : - {community.id} - - {community.summary} -
      -
    • - ))} -
    -
    - )} + + ) : ( <> diff --git a/frontend/src/components/ChatBot/ChatModeToggle.tsx b/frontend/src/components/ChatBot/ChatModeToggle.tsx index a0ebe879a..293706910 100644 --- a/frontend/src/components/ChatBot/ChatModeToggle.tsx +++ b/frontend/src/components/ChatBot/ChatModeToggle.tsx @@ -8,7 +8,7 @@ import { capitalizeWithPlus } from '../../utils/Utils'; import { useCredentials } from '../../context/UserCredentials'; export default function ChatModeToggle({ menuAnchor, - closeHandler = () => {}, + closeHandler = () => { }, open, anchorPortal = true, disableBackdrop = false, @@ -19,7 +19,7 @@ export default function ChatModeToggle({ anchorPortal?: boolean; disableBackdrop?: boolean; }) { - const { setchatMode, chatMode, postProcessingTasks } = useFileContext(); + const { setchatMode, chatMode, postProcessingTasks, selectedRows } = useFileContext(); const isCommunityAllowed = postProcessingTasks.includes('create_communities'); const { isGdsActive } = useCredentials(); const memoizedChatModes = useMemo(() => { @@ -27,34 +27,44 @@ export default function ChatModeToggle({ ? chatModes : chatModes?.filter((m) => !m.mode.includes('entity search+vector')); }, [isGdsActive, isCommunityAllowed]); + + const menuItems = useMemo(() => { - return memoizedChatModes?.map((m) => ({ - title: ( -
    - - {m.mode.includes('+') ? capitalizeWithPlus(m.mode) : capitalize(m.mode)} - + return memoizedChatModes?.map((m) => { + const isDisabled = Boolean(selectedRows.length && !(m.mode === 'vector' || m.mode === 'graph+vector')); + return { + title: (
    - {m.description} + + {m.mode.includes('+') ? capitalizeWithPlus(m.mode) : capitalize(m.mode)} + +
    + {m.description} +
    -
    - ), - onClick: () => { - setchatMode(m.mode); - closeHandler(); // Close the menu after setting the chat mode - }, - disabledCondition: false, - description: ( - - {chatMode === m.mode && ( - <> - Selected - - )} - - ), - })); - }, [chatMode, memoizedChatModes, setchatMode, closeHandler]); + ), + onClick: () => { + setchatMode(m.mode); + closeHandler(); + }, + disabledCondition: isDisabled, + description: ( + + {chatMode === m.mode && ( + <> + Selected + + )} + {isDisabled && ( + <> + Chatmode not available + + )} + + ), + }; + }); + }, [chatMode, memoizedChatModes, setchatMode, closeHandler, selectedRows]); return ( = ({ loading, chunks }) => { + const themeUtils = useContext(ThemeWrapperContext); + + return ( + <> + {loading ? ( + + + + ) : chunks?.length > 0 ? ( +
    +
      + {chunks.map((chunk) => ( +
    • + {chunk?.page_number ? ( + <> +
      + + + {chunk?.fileName} + +
      + Similarity Score: {chunk?.score} + + ) : chunk?.url && chunk?.start_time ? ( + <> +
      + + + + {chunk?.fileName} + + +
      + Similarity Score: {chunk?.score} + + ) : chunk?.url && chunk?.url.includes('wikipedia.org') ? ( + <> +
      + + {chunk?.fileName} +
      + Similarity Score: {chunk?.score} + + ) : chunk?.url && chunk?.url.includes('storage.googleapis.com') ? ( + <> +
      + + {chunk?.fileName} +
      + Similarity Score: {chunk?.score} + + ) : chunk?.url && chunk?.url.startsWith('s3://') ? ( + <> +
      + + {chunk?.fileName} +
      + Similarity Score: {chunk?.score} + + ) : chunk?.url && + !chunk?.url.startsWith('s3://') && + !chunk?.url.includes('storage.googleapis.com') && + !chunk?.url.includes('wikipedia.org') && + !chunk?.url.includes('youtube.com') ? ( + <> +
      + + + {chunk?.url} + +
      + Similarity Score: {chunk?.score} + + ) : ( + <> +
      + {chunk.fileSource === 'local file' ? ( + + ) : ( + + )} + + {chunk.fileName} + +
      + + )} + {chunk?.text} +
    • + ))} +
    +
    + ) : ( + No Chunks Found + )} + + ); +}; + +export default ChunkInfo; diff --git a/frontend/src/components/ChatBot/Communities.tsx b/frontend/src/components/ChatBot/Communities.tsx new file mode 100644 index 000000000..9b530fd0f --- /dev/null +++ b/frontend/src/components/ChatBot/Communities.tsx @@ -0,0 +1,36 @@ +import { Box, LoadingSpinner, Flex, Typography } from '@neo4j-ndl/react'; +import { FC } from 'react'; +import ReactMarkdown from 'react-markdown'; +import { CommunitiesProps } from '../../types'; + +const CommunitiesInfo: FC = ({ loading, communities }) => { + return ( + <> + {loading ? ( + + + + ) : communities?.length > 0 ? ( +
    +
      + {communities.map((community, index) => ( +
    • +
      + + ID : + {community.id} + + {community.summary} +
      +
    • + ))} +
    +
    + ) : ( + No Communities Found + )} + + ); +}; + +export default CommunitiesInfo; diff --git a/frontend/src/components/ChatBot/EntitiesInfo.tsx b/frontend/src/components/ChatBot/EntitiesInfo.tsx new file mode 100644 index 000000000..6c6e0784e --- /dev/null +++ b/frontend/src/components/ChatBot/EntitiesInfo.tsx @@ -0,0 +1,91 @@ +import { Box, GraphLabel, LoadingSpinner, Typography } from '@neo4j-ndl/react'; +import { FC, useMemo } from 'react'; +import { EntitiesProps, GroupedEntity } from '../../types'; +import { calcWordColor } from '@neo4j-devtools/word-color'; +import { graphLabels } from '../../utils/Constants'; +import { parseEntity } from '../../utils/Utils'; + +const EntitiesInfo: FC = ({ loading, mode, graphonly_entities, infoEntities }) => { + const groupedEntities = useMemo<{ [key: string]: GroupedEntity }>(() => { + const items = infoEntities.reduce((acc, entity) => { + const { label, text } = parseEntity(entity); + if (!acc[label]) { + const newColor = calcWordColor(label); + acc[label] = { texts: new Set(), color: newColor }; + } + acc[label].texts.add(text); + return acc; + }, {} as Record; color: string }>); + return items; + }, [infoEntities]); + + const labelCounts = useMemo(() => { + const counts: { [label: string]: number } = {}; + for (let index = 0; index < infoEntities?.length; index++) { + const entity = infoEntities[index]; + const { labels } = entity; + const [label] = labels; + counts[label] = counts[label] ? counts[label] + 1 : 1; + } + return counts; + }, [infoEntities]); + + const sortedLabels = useMemo(() => { + return Object.keys(labelCounts).sort((a, b) => labelCounts[b] - labelCounts[a]); + }, [labelCounts]); + return ( + <> + {loading ? ( + + + + ) : Object.keys(groupedEntities)?.length > 0 || Object.keys(graphonly_entities)?.length > 0 ? ( +
      + {mode == 'graph' + ? graphonly_entities.map((label, index) => ( +
    • +
      + { + // @ts-ignore + label[Object.keys(label)[0]].id ?? Object.keys(label)[0] + } +
      +
    • + )) + : sortedLabels.map((label, index) => { + const entity = groupedEntities[label == 'undefined' ? 'Entity' : label]; + return ( +
    • + e.preventDefault()} + > + {label === '__Community__' ? graphLabels.community : label} ({labelCounts[label]}) + + + {Array.from(entity.texts).slice(0, 3).join(', ')} + +
    • + ); + })} +
    + ) : ( + No Entities Found + )} + + ); +}; + +export default EntitiesInfo; diff --git a/frontend/src/components/ChatBot/SourcesInfo.tsx b/frontend/src/components/ChatBot/SourcesInfo.tsx new file mode 100644 index 000000000..fd5d89949 --- /dev/null +++ b/frontend/src/components/ChatBot/SourcesInfo.tsx @@ -0,0 +1,139 @@ +import { FC, useContext } from 'react'; +import { SourcesProps } from '../../types'; +import { Box, LoadingSpinner, TextLink, Typography } from '@neo4j-ndl/react'; +import { DocumentTextIconOutline, GlobeAltIconOutline } from '@neo4j-ndl/react/icons'; +import { getLogo, youtubeLinkValidation } from '../../utils/Utils'; +import { ThemeWrapperContext } from '../../context/ThemeWrapper'; +import HoverableLink from '../UI/HoverableLink'; +import wikipedialogo from '../../assets/images/wikipedia.svg'; +import youtubelogo from '../../assets/images/youtube.svg'; +import gcslogo from '../../assets/images/gcs.webp'; +import s3logo from '../../assets/images/s3logo.png'; + +const SourcesInfo: FC = ({ loading, mode, chunks, sources }) => { + const themeUtils = useContext(ThemeWrapperContext); + return ( + <> + {loading ? ( + + + + ) : mode === 'entity search+vector' && chunks?.length ? ( +
      + {chunks + .map((c) => ({ fileName: c.fileName, fileSource: c.fileSource })) + .map((s, index) => { + return ( +
    • +
      + {s.fileSource === 'local file' ? ( + + ) : ( + + )} + + {s.fileName} + +
      +
    • + ); + })} +
    + ) : sources?.length ? ( +
      + {sources.map((link, index) => { + return ( +
    • + {link?.startsWith('http') || link?.startsWith('https') ? ( + <> + {link?.includes('wikipedia.org') && ( +
      + Wikipedia Logo + + + + {link} + + + +
      + )} + {link?.includes('storage.googleapis.com') && ( +
      + Google Cloud Storage Logo + + {decodeURIComponent(link).split('/').at(-1)?.split('?')[0] ?? 'GCS File'} + +
      + )} + {youtubeLinkValidation(link) && ( + <> +
      + + + + + {link} + + + +
      + + )} + {!link?.startsWith('s3://') && + !link?.includes('storage.googleapis.com') && + !link?.includes('wikipedia.org') && + !link?.includes('youtube.com') && ( +
      + + + {link} + +
      + )} + + ) : link?.startsWith('s3://') ? ( +
      + S3 Logo + + {decodeURIComponent(link).split('/').at(-1) ?? 'S3 File'} + +
      + ) : ( +
      + + + {link} + +
      + )} +
    • + ); + })} +
    + ) : ( + No Sources Found + )} + + ); +}; + +export default SourcesInfo; diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 679756dd9..9631335a9 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -644,3 +644,27 @@ export interface DatabaseStatusProps { isGdsActive: boolean; uri: string | null; } + +export type SourcesProps = { + loading: boolean; + mode: string; + sources: string[]; + chunks: Chunk[]; +}; + +export type ChunkProps = { + loading: boolean; + chunks: Chunk[]; +}; + +export type EntitiesProps = { + loading: boolean; + mode: string; + graphonly_entities: []; + infoEntities: Entity[]; +}; + +export type CommunitiesProps = { + loading: boolean; + communities: Community[]; +}; diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index b59c082fd..82a7cda3e 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -449,3 +449,14 @@ export const getLogo = (mode: string): Record => { 'gcs bucket': gcslogo, }; }; + +export const generateYouTubeLink = (url: string, startTime: string) => { + try { + const urlObj = new URL(url); + urlObj.searchParams.set('t', startTime); + return urlObj.toString(); + } catch (error) { + console.error('Invalid URL:', error); + return ''; + } +}; From f0810c7da834466d5878e55f4784d2f5a7cb51b8 Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Wed, 18 Sep 2024 13:17:43 +0000 Subject: [PATCH 103/292] aria label addition --- .../GraphEnhancementDialog/PostProcessingCheckList/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/index.tsx index 0051fefbf..28114ced7 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/index.tsx @@ -45,6 +45,7 @@ export default function PostProcessingCheckList() { } }} disabled={isCreateCommunities && !isGdsActive} + aria-label='checkbox-postProcessing' /> {job.description}
    From 869c87e4185d904eb81dccf5794bf7402894bb3a Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Thu, 19 Sep 2024 05:10:32 +0000 Subject: [PATCH 104/292] code improvements used URL class for host url check --- frontend/src/components/ChatBot/ChatModeToggle.tsx | 3 +-- frontend/src/components/ChatBot/ChunkInfo.tsx | 10 ++++------ frontend/src/utils/Utils.ts | 8 ++++++++ 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/frontend/src/components/ChatBot/ChatModeToggle.tsx b/frontend/src/components/ChatBot/ChatModeToggle.tsx index 293706910..d8f1f99c9 100644 --- a/frontend/src/components/ChatBot/ChatModeToggle.tsx +++ b/frontend/src/components/ChatBot/ChatModeToggle.tsx @@ -8,7 +8,7 @@ import { capitalizeWithPlus } from '../../utils/Utils'; import { useCredentials } from '../../context/UserCredentials'; export default function ChatModeToggle({ menuAnchor, - closeHandler = () => { }, + closeHandler = () => {}, open, anchorPortal = true, disableBackdrop = false, @@ -28,7 +28,6 @@ export default function ChatModeToggle({ : chatModes?.filter((m) => !m.mode.includes('entity search+vector')); }, [isGdsActive, isCommunityAllowed]); - const menuItems = useMemo(() => { return memoizedChatModes?.map((m) => { const isDisabled = Boolean(selectedRows.length && !(m.mode === 'vector' || m.mode === 'graph+vector')); diff --git a/frontend/src/components/ChatBot/ChunkInfo.tsx b/frontend/src/components/ChatBot/ChunkInfo.tsx index eb7b435bb..350b41b98 100644 --- a/frontend/src/components/ChatBot/ChunkInfo.tsx +++ b/frontend/src/components/ChatBot/ChunkInfo.tsx @@ -7,7 +7,7 @@ import youtubelogo from '../../assets/images/youtube.svg'; import gcslogo from '../../assets/images/gcs.webp'; import s3logo from '../../assets/images/s3logo.png'; import ReactMarkdown from 'react-markdown'; -import { generateYouTubeLink, getLogo } from '../../utils/Utils'; +import { generateYouTubeLink, getLogo, isAllowedHost } from '../../utils/Utils'; import { ThemeWrapperContext } from '../../context/ThemeWrapper'; const ChunkInfo: FC = ({ loading, chunks }) => { @@ -52,7 +52,7 @@ const ChunkInfo: FC = ({ loading, chunks }) => { Similarity Score: {chunk?.score} - ) : chunk?.url && chunk?.url.includes('wikipedia.org') ? ( + ) : chunk?.url && new URL(chunk.url).host === 'wikipedia.org' ? ( <>
    @@ -60,7 +60,7 @@ const ChunkInfo: FC = ({ loading, chunks }) => {
    Similarity Score: {chunk?.score} - ) : chunk?.url && chunk?.url.includes('storage.googleapis.com') ? ( + ) : chunk?.url && new URL(chunk.url).host === 'storage.googleapis.com' ? ( <>
    @@ -78,9 +78,7 @@ const ChunkInfo: FC = ({ loading, chunks }) => { ) : chunk?.url && !chunk?.url.startsWith('s3://') && - !chunk?.url.includes('storage.googleapis.com') && - !chunk?.url.includes('wikipedia.org') && - !chunk?.url.includes('youtube.com') ? ( + !isAllowedHost(chunk?.url, ['storage.googleapis.com', 'wikipedia.org', 'youtube.com']) ? ( <>
    diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index 82a7cda3e..50ce37c3e 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -460,3 +460,11 @@ export const generateYouTubeLink = (url: string, startTime: string) => { return ''; } }; +export function isAllowedHost(url: string, allowedHosts: string[]) { + try { + const parsedUrl = new URL(url); + return allowedHosts.includes(parsedUrl.host); + } catch (e) { + return false; + } +} From b2097e5a1d5acd5cc10ff4104364a1fae24904b9 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Thu, 19 Sep 2024 05:17:39 +0000 Subject: [PATCH 105/292] host level check --- frontend/src/components/ChatBot/SourcesInfo.tsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/ChatBot/SourcesInfo.tsx b/frontend/src/components/ChatBot/SourcesInfo.tsx index fd5d89949..91fee511f 100644 --- a/frontend/src/components/ChatBot/SourcesInfo.tsx +++ b/frontend/src/components/ChatBot/SourcesInfo.tsx @@ -2,7 +2,7 @@ import { FC, useContext } from 'react'; import { SourcesProps } from '../../types'; import { Box, LoadingSpinner, TextLink, Typography } from '@neo4j-ndl/react'; import { DocumentTextIconOutline, GlobeAltIconOutline } from '@neo4j-ndl/react/icons'; -import { getLogo, youtubeLinkValidation } from '../../utils/Utils'; +import { getLogo, isAllowedHost, youtubeLinkValidation } from '../../utils/Utils'; import { ThemeWrapperContext } from '../../context/ThemeWrapper'; import HoverableLink from '../UI/HoverableLink'; import wikipedialogo from '../../assets/images/wikipedia.svg'; @@ -49,7 +49,7 @@ const SourcesInfo: FC = ({ loading, mode, chunks, sources }) => {
  • {link?.startsWith('http') || link?.startsWith('https') ? ( <> - {link?.includes('wikipedia.org') && ( + {isAllowedHost(link, ['wikipedia.org']) && (
    Wikipedia Logo @@ -64,7 +64,7 @@ const SourcesInfo: FC = ({ loading, mode, chunks, sources }) => {
    )} - {link?.includes('storage.googleapis.com') && ( + {isAllowedHost(link, ['storage.googleapis.com']) && (
    Google Cloud Storage Logo = ({ loading, mode, chunks, sources }) => { )} {!link?.startsWith('s3://') && - !link?.includes('storage.googleapis.com') && - !link?.includes('wikipedia.org') && - !link?.includes('youtube.com') && ( + !isAllowedHost(link, ['storage.googleapis.com', 'wikipedia.org', 'youtube.com']) && (
    From 3819118bfd40e815944db85beca9f54a9f68415f Mon Sep 17 00:00:00 2001 From: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Date: Thu, 19 Sep 2024 06:18:43 +0000 Subject: [PATCH 106/292] Update Security header --- backend/score.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/score.py b/backend/score.py index cecc42778..74d22759f 100644 --- a/backend/score.py +++ b/backend/score.py @@ -49,7 +49,7 @@ def sick(): app = FastAPI() SecWeb(app=app, Option={'referrer': False, 'xframe': False}) app.add_middleware(HSTS, Option={'max-age': 4}) -app.add_middleware(ContentSecurityPolicy, Option={'default-src': ["'self'"], 'base-uri': ["'self'"], 'block-all-mixed-content': []}, script_nonce=False, style_nonce=False, report_only=False) +app.add_middleware(ContentSecurityPolicy, Option={'default-src': ["'self'"], 'base-uri': ["'self'"], 'block-all-mixed-content': [], 'clearSiteData': {'cache': False, 'storage': False}, 'cacheControl': {'public': False, 's-maxage': 0}}, script_nonce=False, style_nonce=False, report_only=False) app.add_middleware(XContentTypeOptions) app.add_middleware(XFrame, Option={'X-Frame-Options': 'DENY'}) From 1246b41c80276dbf20035f5abae99a035dbb718c Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Thu, 19 Sep 2024 07:06:00 +0000 Subject: [PATCH 107/292] encryption of localstorage values --- frontend/src/components/Content.tsx | 10 ++++++++-- .../Popups/ConnectionModal/ConnectionModal.tsx | 6 ++++-- frontend/src/services/CancelAPI.ts | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index f76e45cb4..517ada241 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -111,7 +111,7 @@ const Content: React.FC = ({ setUserCredentials({ uri: neo4jConnection.uri, userName: neo4jConnection.user, - password: neo4jConnection.password, + password: atob(neo4jConnection.password), database: neo4jConnection.database, port: neo4jConnection.uri.split(':')[2], }); @@ -172,13 +172,19 @@ const Content: React.FC = ({ (async () => { const parsedData = JSON.parse(connection); console.log(parsedData.uri); - const response = await connectAPI(parsedData.uri, parsedData.user, parsedData.password, parsedData.database); + const response = await connectAPI( + parsedData.uri, + parsedData.user, + atob(parsedData.password), + parsedData.database + ); if (response?.data?.status === 'Success') { localStorage.setItem( 'neo4j.connection', JSON.stringify({ ...parsedData, userDbVectorIndex: response.data.data.db_vector_dimension, + password: btoa(atob(parsedData.password)), }) ); if ( diff --git a/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx b/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx index 6b0a986dc..0213e9502 100644 --- a/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx +++ b/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx @@ -84,7 +84,7 @@ export default function ConnectionModal({ JSON.stringify({ uri: usercredential?.uri, user: usercredential?.userName, - password: usercredential?.password, + password: btoa(usercredential?.password), database: usercredential?.database, userDbVectorIndex: 384, }) @@ -189,6 +189,7 @@ export default function ConnectionModal({ setMessage({ type: 'danger', content: 'Please drop a valid file' }); } } catch (err: any) { + console.log({ err }); setMessage({ type: 'danger', content: err.message }); } } @@ -213,7 +214,7 @@ export default function ConnectionModal({ JSON.stringify({ uri: connectionURI, user: username, - password: password, + password: btoa(password), database: database, userDbVectorIndex, isgdsActive, @@ -262,6 +263,7 @@ export default function ConnectionModal({ } } } catch (error) { + console.log({ error }); setIsLoading(false); if (error instanceof Error) { setMessage({ type: 'danger', content: error.message }); diff --git a/frontend/src/services/CancelAPI.ts b/frontend/src/services/CancelAPI.ts index de3ea9ba0..f491f06e0 100644 --- a/frontend/src/services/CancelAPI.ts +++ b/frontend/src/services/CancelAPI.ts @@ -9,7 +9,7 @@ const cancelAPI = async (filenames: string[], source_types: string[]) => { formData.append('uri', credentials?.uri ?? ''); formData.append('database', credentials?.database ?? ''); formData.append('userName', credentials?.user ?? ''); - formData.append('password', credentials?.password ?? ''); + formData.append('password', atob(credentials?.password) ?? ''); } formData.append('filenames', JSON.stringify(filenames)); formData.append('source_types', JSON.stringify(source_types)); From 1709a162eb2af7d8fe02f128011c4182d50fb932 Mon Sep 17 00:00:00 2001 From: Prakriti Solankey Date: Thu, 19 Sep 2024 17:11:01 +0530 Subject: [PATCH 108/292] 'mode-selection-changes' --- backend/score.py | 5 --- .../src/components/ChatBot/ChatModeToggle.tsx | 34 +++++++++++++++---- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/backend/score.py b/backend/score.py index e47905363..e87fc618e 100644 --- a/backend/score.py +++ b/backend/score.py @@ -48,11 +48,6 @@ def sick(): return False app = FastAPI() -SecWeb(app=app, Option={'referrer': False, 'xframe': False}) -app.add_middleware(HSTS, Option={'max-age': 4, 'preload': True}) -app.add_middleware(ContentSecurityPolicy, Option={'default-src': ["'self'"], 'base-uri': ["'self'"], 'block-all-mixed-content': []}, script_nonce=False, style_nonce=False, report_only=False) -app.add_middleware(XContentTypeOptions) -app.add_middleware(XFrame, Option={'X-Frame-Options': 'DENY'}) app.add_middleware( CORSMiddleware, diff --git a/frontend/src/components/ChatBot/ChatModeToggle.tsx b/frontend/src/components/ChatBot/ChatModeToggle.tsx index d8f1f99c9..944157f1e 100644 --- a/frontend/src/components/ChatBot/ChatModeToggle.tsx +++ b/frontend/src/components/ChatBot/ChatModeToggle.tsx @@ -1,5 +1,5 @@ import { StatusIndicator, Typography } from '@neo4j-ndl/react'; -import { useMemo } from 'react'; +import { useMemo, useEffect } from 'react'; import { useFileContext } from '../../context/UsersFiles'; import CustomMenu from '../UI/Menu'; import { chatModes } from '../../utils/Constants'; @@ -8,7 +8,7 @@ import { capitalizeWithPlus } from '../../utils/Utils'; import { useCredentials } from '../../context/UserCredentials'; export default function ChatModeToggle({ menuAnchor, - closeHandler = () => {}, + closeHandler = () => { }, open, anchorPortal = true, disableBackdrop = false, @@ -22,15 +22,31 @@ export default function ChatModeToggle({ const { setchatMode, chatMode, postProcessingTasks, selectedRows } = useFileContext(); const isCommunityAllowed = postProcessingTasks.includes('create_communities'); const { isGdsActive } = useCredentials(); + + useEffect(() => { + if (selectedRows.length !== 0) { + setchatMode('graph+vector'); + } else { + setchatMode('graph+vector+fulltext'); + } + }, [selectedRows]); + const memoizedChatModes = useMemo(() => { return isGdsActive && isCommunityAllowed ? chatModes : chatModes?.filter((m) => !m.mode.includes('entity search+vector')); }, [isGdsActive, isCommunityAllowed]); - const menuItems = useMemo(() => { return memoizedChatModes?.map((m) => { const isDisabled = Boolean(selectedRows.length && !(m.mode === 'vector' || m.mode === 'graph+vector')); + const handleModeChange = () => { + if (isDisabled) { + setchatMode('graph+vector'); + } else { + setchatMode(m.mode); + } + closeHandler(); + }; return { title: (
    @@ -42,10 +58,7 @@ export default function ChatModeToggle({
    ), - onClick: () => { - setchatMode(m.mode); - closeHandler(); - }, + onClick: handleModeChange, disabledCondition: isDisabled, description: ( @@ -64,6 +77,13 @@ export default function ChatModeToggle({ }; }); }, [chatMode, memoizedChatModes, setchatMode, closeHandler, selectedRows]); + + useEffect(() => { + if (!selectedRows.length && !chatMode) { + setchatMode(chatMode); + } + }, [setchatMode, selectedRows, chatMode]); + return ( Date: Thu, 19 Sep 2024 12:20:47 +0000 Subject: [PATCH 109/292] added local chat history --- backend/src/QA_integration.py | 53 +++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/backend/src/QA_integration.py b/backend/src/QA_integration.py index d28459a9b..eb6ac5be1 100644 --- a/backend/src/QA_integration.py +++ b/backend/src/QA_integration.py @@ -19,6 +19,7 @@ from langchain_text_splitters import TokenTextSplitter from langchain_core.messages import HumanMessage, AIMessage from langchain.chains import GraphCypherQAChain +from langchain_community.chat_message_histories import ChatMessageHistory # LangChain chat models from langchain_openai import ChatOpenAI, AzureChatOpenAI @@ -37,7 +38,29 @@ load_dotenv() EMBEDDING_MODEL = os.getenv('EMBEDDING_MODEL') -EMBEDDING_FUNCTION , _ = load_embedding_model(EMBEDDING_MODEL) +EMBEDDING_FUNCTION , _ = load_embedding_model(EMBEDDING_MODEL) + + + +class SessionChatHistory: + history_dict = {} + + @classmethod + def get_chat_history(cls, session_id): + """Retrieve or create chat message history for a given session ID.""" + if session_id not in cls.history_dict: + logging.info(f"Creating new ChatMessageHistory Local for session ID: {session_id}") + cls.history_dict[session_id] = ChatMessageHistory() + else: + logging.info(f"Retrieved existing ChatMessageHistory Local for session ID: {session_id}") + return cls.history_dict[session_id] + +def get_history_by_session_id(session_id): + try: + return SessionChatHistory.get_chat_history(session_id) + except Exception as e: + logging.error(f"Failed to get history for session ID '{session_id}': {e}") + raise def get_total_tokens(ai_response, llm): try: @@ -68,12 +91,15 @@ def get_total_tokens(ai_response, llm): return total_tokens -def clear_chat_history(graph, session_id): +def clear_chat_history(graph, session_id,local=False): try: - history = Neo4jChatMessageHistory( - graph=graph, - session_id=session_id - ) + if not local: + history = Neo4jChatMessageHistory( + graph=graph, + session_id=session_id + ) + else: + history = get_history_by_session_id(session_id) history.clear() @@ -534,17 +560,20 @@ def process_graph_response(model, graph, question, messages, history): "user": "chatbot" } -def create_neo4j_chat_message_history(graph, session_id): +def create_neo4j_chat_message_history(graph, session_id, local=False): """ Creates and returns a Neo4jChatMessageHistory instance. """ try: - - history = Neo4jChatMessageHistory( - graph=graph, - session_id=session_id - ) + if not local: + history = Neo4jChatMessageHistory( + graph=graph, + session_id=session_id + ) + return history + + history = get_history_by_session_id(session_id) return history except Exception as e: From 9210bf8a226ced845542ce6cb8efda052a12c682 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Thu, 19 Sep 2024 13:09:35 +0000 Subject: [PATCH 110/292] added neo4j from existing index to entity vector mode --- backend/src/QA_integration.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/backend/src/QA_integration.py b/backend/src/QA_integration.py index d28459a9b..7ac99f66b 100644 --- a/backend/src/QA_integration.py +++ b/backend/src/QA_integration.py @@ -287,13 +287,14 @@ def initialize_neo4j_vector(graph, chat_mode_settings): keyword_index_name=keyword_index ) logging.info(f"Successfully retrieved Neo4jVector Fulltext index '{index_name}' and keyword index '{keyword_index}'") + elif mode == "entity search+vector": + neo_db = Neo4jVector.from_existing_index( + embedding=EMBEDDING_FUNCTION, + index_name=index_name, + retrieval_query=retrieval_query, + graph=graph + ) else: - # neo_db = Neo4jVector.from_existing_index( - # embedding=EMBEDDING_FUNCTION, - # index_name=index_name, - # retrieval_query=retrieval_query, - # graph=graph - # ) neo_db = Neo4jVector.from_existing_graph( embedding=EMBEDDING_FUNCTION, index_name=index_name, @@ -303,7 +304,6 @@ def initialize_neo4j_vector(graph, chat_mode_settings): embedding_node_property="embedding", text_node_properties=["text"] ) - logging.info(f"Successfully retrieved Neo4jVector index '{index_name}'") except Exception as e: index_name = chat_mode_settings.get("index_name") From b5b8545edf2d635c2ff1ca1f60862954be2b5bf8 Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Thu, 19 Sep 2024 13:21:07 +0000 Subject: [PATCH 111/292] label changes --- backend/src/chunkid_entities.py | 6 ++++ backend/src/graph_query.py | 2 ++ .../src/components/ChatBot/ChatInfoModal.tsx | 29 ++++++++-------- .../src/components/ChatBot/ChatModeToggle.tsx | 16 ++++----- frontend/src/components/ChatBot/Chatbot.tsx | 4 +-- frontend/src/context/UsersFiles.tsx | 4 +-- frontend/src/utils/Constants.ts | 34 ++++++++++++------- frontend/src/utils/Utils.ts | 13 +++---- 8 files changed, 64 insertions(+), 44 deletions(-) diff --git a/backend/src/chunkid_entities.py b/backend/src/chunkid_entities.py index 3fd3c3a71..aa8d1d4ca 100644 --- a/backend/src/chunkid_entities.py +++ b/backend/src/chunkid_entities.py @@ -22,6 +22,8 @@ def process_records(records): if "labels" in start_node.keys(): labels = set(start_node["labels"]) labels.discard("__Entity__") + if not labels: + labels.add('*') start_node["labels"] = list(labels) nodes.append(start_node) seen_nodes.add(start_node['element_id']) @@ -30,6 +32,8 @@ def process_records(records): if "labels" in end_node.keys(): labels = set(end_node["labels"]) labels.discard("__Entity__") + if not labels: + labels.add('*') end_node["labels"] = list(labels) nodes.append(end_node) seen_nodes.add(end_node['element_id']) @@ -106,6 +110,8 @@ def remove_duplicate_nodes(nodes,property="element_id"): if "labels" in node.keys(): labels = set(node["labels"]) labels.discard("__Entity__") + if not labels: + labels.add('*') node["labels"] = list(labels) unique_nodes.append(node) seen_element_ids.add(element_id) diff --git a/backend/src/graph_query.py b/backend/src/graph_query.py index 77f6e9d0a..fb7333b48 100644 --- a/backend/src/graph_query.py +++ b/backend/src/graph_query.py @@ -63,6 +63,8 @@ def process_node(node): try: labels = set(node.labels) labels.discard("__Entity__") + if not labels: + labels.add('*') node_element = { "element_id": node.element_id, diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index 82fa25e26..53172256a 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -31,6 +31,7 @@ import ChunkInfo from './ChunkInfo'; import EntitiesInfo from './EntitiesInfo'; import SourcesInfo from './SourcesInfo'; import CommunitiesInfo from './Communities'; +import { chatModeLables } from '../../utils/Constants'; const ChatInfoModal: React.FC = ({ sources, @@ -45,7 +46,7 @@ const ChatInfoModal: React.FC = ({ }) => { const { breakpoints } = tokens; const isTablet = useMediaQuery(`(min-width:${breakpoints.xs}) and (max-width: ${breakpoints.lg})`); - const [activeTab, setActiveTab] = useState(error?.length ? 10 : mode === 'graph' ? 4 : 3); + const [activeTab, setActiveTab] = useState(error?.length ? 10 : mode === chatModeLables.graph ? 4 : 3); const [infoEntities, setInfoEntities] = useState([]); const [communities, setCommunities] = useState([]); const [loading, setLoading] = useState(false); @@ -81,7 +82,7 @@ const ChatInfoModal: React.FC = ({ ); useEffect(() => { - if (mode != 'graph' || error?.trim() !== '') { + if (mode != chatModeLables.graph || error?.trim() !== '') { (async () => { setLoading(true); try { @@ -89,7 +90,7 @@ const ChatInfoModal: React.FC = ({ userCredentials as UserCredentials, chunk_ids.map((c) => c.id).join(','), userCredentials?.database, - mode === 'entity search+vector' + mode === chatModeLables.entity_vector ); if (response.data.status === 'Failure') { throw new Error(response.data.error); @@ -101,7 +102,7 @@ const ChatInfoModal: React.FC = ({ setInfoEntities( nodesData.map((n: Entity) => { - if (!n.labels.length && mode === 'entity search+vector') { + if (!n.labels.length && mode === chatModeLables.entity_vector) { return { ...n, labels: ['Entity'], @@ -112,7 +113,7 @@ const ChatInfoModal: React.FC = ({ ); setNodes( nodesData.map((n: ExtendedNode) => { - if (!n.labels.length && mode === 'entity search+vector') { + if (!n.labels.length && mode === chatModeLables.entity_vector) { return { ...n, labels: ['Entity'], @@ -174,22 +175,22 @@ const ChatInfoModal: React.FC = ({ {error} ) : ( - {mode != 'graph' ? Sources used : <>} - {mode != 'graph' ? Chunks : <>} - {mode === 'graph+vector' || - mode === 'graph' || - mode === 'graph+vector+fulltext' || - mode === 'entity search+vector' ? ( + {mode != chatModeLables.graph ? Sources used : <>} + {mode != chatModeLables.graph ? Chunks : <>} + {mode === chatModeLables.graph_vector || + mode === chatModeLables.graph || + mode === chatModeLables.graph_vector_fulltext || + mode === chatModeLables.entity_vector ? ( Top Entities used ) : ( <> )} - {mode === 'graph' && cypher_query?.trim()?.length ? ( + {mode === chatModeLables.graph && cypher_query?.trim()?.length ? ( Generated Cypher Query ) : ( <> )} - {mode === 'entity search+vector' ? Communities : <>} + {mode === chatModeLables.entity_vector? Communities : <>} )} @@ -216,7 +217,7 @@ const ChatInfoModal: React.FC = ({ className='min-h-40' /> - {mode === 'entity search+vector' ? ( + {mode === chatModeLables.entity_vector ? ( diff --git a/frontend/src/components/ChatBot/ChatModeToggle.tsx b/frontend/src/components/ChatBot/ChatModeToggle.tsx index 944157f1e..6c9bf459f 100644 --- a/frontend/src/components/ChatBot/ChatModeToggle.tsx +++ b/frontend/src/components/ChatBot/ChatModeToggle.tsx @@ -2,7 +2,7 @@ import { StatusIndicator, Typography } from '@neo4j-ndl/react'; import { useMemo, useEffect } from 'react'; import { useFileContext } from '../../context/UsersFiles'; import CustomMenu from '../UI/Menu'; -import { chatModes } from '../../utils/Constants'; +import { chatModeLables, chatModes } from '../../utils/Constants'; import { capitalize } from '@mui/material'; import { capitalizeWithPlus } from '../../utils/Utils'; import { useCredentials } from '../../context/UserCredentials'; @@ -25,23 +25,23 @@ export default function ChatModeToggle({ useEffect(() => { if (selectedRows.length !== 0) { - setchatMode('graph+vector'); + setchatMode(chatModeLables.graph_vector); } else { - setchatMode('graph+vector+fulltext'); + setchatMode(chatModeLables.graph_vector_fulltext); } }, [selectedRows]); const memoizedChatModes = useMemo(() => { return isGdsActive && isCommunityAllowed ? chatModes - : chatModes?.filter((m) => !m.mode.includes('entity search+vector')); + : chatModes?.filter((m) => !m.mode.includes(chatModeLables.entity_vector)); }, [isGdsActive, isCommunityAllowed]); const menuItems = useMemo(() => { return memoizedChatModes?.map((m) => { - const isDisabled = Boolean(selectedRows.length && !(m.mode === 'vector' || m.mode === 'graph+vector')); + const isDisabled = Boolean(selectedRows.length && !(m.mode === chatModeLables.vector || m.mode === chatModeLables.graph_vector)); const handleModeChange = () => { if (isDisabled) { - setchatMode('graph+vector'); + setchatMode(chatModeLables.graph_vector); } else { setchatMode(m.mode); } @@ -64,12 +64,12 @@ export default function ChatModeToggle({ {chatMode === m.mode && ( <> - Selected + {chatModeLables.selected} )} {isDisabled && ( <> - Chatmode not available + {chatModeLables.unavailableChatMode} )} diff --git a/frontend/src/components/ChatBot/Chatbot.tsx b/frontend/src/components/ChatBot/Chatbot.tsx index 5e931ad35..412f485ed 100644 --- a/frontend/src/components/ChatBot/Chatbot.tsx +++ b/frontend/src/components/ChatBot/Chatbot.tsx @@ -15,7 +15,7 @@ import { useFileContext } from '../../context/UsersFiles'; import clsx from 'clsx'; import ReactMarkdown from 'react-markdown'; import { IconButtonWithToolTip } from '../UI/IconButtonToolTip'; -import { buttonCaptions, tooltips } from '../../utils/Constants'; +import { buttonCaptions, chatModeLables, tooltips } from '../../utils/Constants'; import useSpeechSynthesis from '../../hooks/useSpeech'; import ButtonWithToolTip from '../UI/ButtonWithToolTip'; import FallBackDialog from '../UI/FallBackDialog'; @@ -44,7 +44,7 @@ const Chatbot: FC = (props) => { const [tokensUsed, setTokensUsed] = useState(0); const [cypherQuery, setcypherQuery] = useState(''); const [copyMessageId, setCopyMessageId] = useState(null); - const [chatsMode, setChatsMode] = useState('graph+vector'); + const [chatsMode, setChatsMode] = useState(chatModeLables.graph_vector); const [graphEntitites, setgraphEntitites] = useState<[]>([]); const [messageError, setmessageError] = useState(''); diff --git a/frontend/src/context/UsersFiles.tsx b/frontend/src/context/UsersFiles.tsx index df805504e..fbab1b719 100644 --- a/frontend/src/context/UsersFiles.tsx +++ b/frontend/src/context/UsersFiles.tsx @@ -1,6 +1,6 @@ import { createContext, useContext, useState, Dispatch, SetStateAction, FC, useEffect } from 'react'; import { CustomFile, FileContextProviderProps, OptionType } from '../types'; -import { defaultLLM } from '../utils/Constants'; +import { chatModeLables, defaultLLM } from '../utils/Constants'; import { useCredentials } from './UserCredentials'; import Queue from '../utils/Queue'; interface showTextFromSchemaDialogType { @@ -58,7 +58,7 @@ const FileContextProvider: FC = ({ children }) => { const [selectedSchemas, setSelectedSchemas] = useState([]); const [rowSelection, setRowSelection] = useState>({}); const [selectedRows, setSelectedRows] = useState([]); - const [chatMode, setchatMode] = useState('graph+vector+fulltext'); + const [chatMode, setchatMode] = useState(chatModeLables.graph_vector_fulltext); const [isSchema, setIsSchema] = useState(false); const [showTextFromSchemaDialog, setShowTextFromSchemaDialog] = useState({ triggeredFrom: '', diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index e5cb806c8..0b2f60cba 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -65,6 +65,16 @@ export const defaultLLM = llms?.includes('openai-gpt-4o') // ? process.env.VITE_CHAT_MODES?.split(',') // : ['vector', 'graph', 'graph+vector', 'fulltext', 'graph+vector+fulltext', 'local community', 'global community']; +export const chatModeLables = { + vector: 'vector', + graph : 'graph', + graph_vector: 'graph+vector', + fulltext: 'fulltext', + graph_vector_fulltext: 'graph+vector+fulltext', + entity_vector:'entity search+vector', + unavailableChatMode: 'Chat mode is unavailable when rows are selected', + selected:'Selected' +} export const chatModes = process.env?.VITE_CHAT_MODES?.trim() != '' ? process.env.VITE_CHAT_MODES?.split(',').map((mode) => ({ @@ -73,33 +83,33 @@ export const chatModes = })) : [ { - mode: 'vector', - description: 'Utilizes vector indexing on text chunks to enable semantic similarity search.', + mode: chatModeLables.vector, + description: 'Performs semantic similarity search on text chunks using vector indexing.', }, { - mode: 'graph', + mode: chatModeLables.graph, description: - 'Leverages text-to-cypher translation to query a database and retrieve relevant data, ensuring a highly targeted and contextually accurate response.', + 'Translates text to Cypher queries for precise data retrieval from a graph database.' }, { - mode: 'graph+vector', + mode: chatModeLables.graph_vector, description: - 'Combines vector indexing on text chunks with graph connections, enhancing search results with contextual relevance by considering relationships between concepts.', + 'Combines vector indexing and graph connections for contextually enhanced semantic search.', }, { - mode: 'fulltext', + mode: chatModeLables.fulltext, description: - 'Employs a fulltext index on text chunks for rapid keyword-based search, efficiently identifying documents containing specific words or phrases.', + 'Conducts fast, keyword-based search using full-text indexing on text chunks.', }, { - mode: 'graph+vector+fulltext', + mode: chatModeLables.graph_vector_fulltext, description: - 'Merges vector indexing, graph connections, and fulltext indexing for a comprehensive search approach, combining semantic similarity, contextual relevance, and keyword-based search for optimal results.', + 'Integrates vector, graph, and full-text indexing for comprehensive search results.', }, { - mode: 'entity search+vector', + mode: chatModeLables.entity_vector, description: - 'Combines entity node vector indexing with graph connections for accurate entity-based search, providing the most relevant response.', + 'Uses vector indexing on entity nodes for highly relevant entity-based search.', }, ]; diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index 50ce37c3e..97e7bda07 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -19,6 +19,7 @@ import youtubedarklogo from '../assets/images/youtube-darkmode.svg'; import youtubelightlogo from '../assets/images/youtube-lightmode.svg'; import s3logo from '../assets/images/s3logo.png'; import gcslogo from '../assets/images/gcs.webp'; +import { chatModeLables } from './Constants'; // Get the Url export const url = () => { @@ -415,17 +416,17 @@ export const capitalizeWithPlus = (s: string) => { export const getDescriptionForChatMode = (mode: string): string => { switch (mode.toLowerCase()) { - case 'vector': + case chatModeLables.vector: return 'Utilizes vector indexing on text chunks to enable semantic similarity search.'; - case 'graph': + case chatModeLables.graph: return 'Leverages text-to-cypher translation to query a database and retrieve relevant data, ensuring a highly targeted and contextually accurate response.'; - case 'graph+vector': + case chatModeLables.graph_vector: return 'Combines vector indexing on text chunks with graph connections, enhancing search results with contextual relevance by considering relationships between concepts.'; - case 'fulltext': + case chatModeLables.fulltext: return 'Employs a fulltext index on text chunks for rapid keyword-based search, efficiently identifying documents containing specific words or phrases.'; - case 'graph+vector+fulltext': + case chatModeLables.graph_vector_fulltext: return 'Merges vector indexing, graph connections, and fulltext indexing for a comprehensive search approach, combining semantic similarity, contextual relevance, and keyword-based search for optimal results.'; - case 'entity search+vector': + case chatModeLables.entity_vector: return 'Combines entity node vector indexing with graph connections for accurate entity-based search, providing the most relevant response.'; default: return 'Chat mode description not available'; // Fallback description From adf41067ad5883aff927498cf9857ed211be27f4 Mon Sep 17 00:00:00 2001 From: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Date: Thu, 19 Sep 2024 15:54:25 +0000 Subject: [PATCH 112/292] commented security header --- backend/score.py | 8 ++++---- backend/src/main.py | 30 ++++++++++++++++++++---------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/backend/score.py b/backend/score.py index 74d22759f..891444e62 100644 --- a/backend/score.py +++ b/backend/score.py @@ -48,10 +48,10 @@ def sick(): app = FastAPI() SecWeb(app=app, Option={'referrer': False, 'xframe': False}) -app.add_middleware(HSTS, Option={'max-age': 4}) -app.add_middleware(ContentSecurityPolicy, Option={'default-src': ["'self'"], 'base-uri': ["'self'"], 'block-all-mixed-content': [], 'clearSiteData': {'cache': False, 'storage': False}, 'cacheControl': {'public': False, 's-maxage': 0}}, script_nonce=False, style_nonce=False, report_only=False) -app.add_middleware(XContentTypeOptions) -app.add_middleware(XFrame, Option={'X-Frame-Options': 'DENY'}) +# app.add_middleware(HSTS, Option={'max-age': 4}) +# app.add_middleware(ContentSecurityPolicy, Option={'default-src': ["'self'"], 'base-uri': ["'self'"], 'block-all-mixed-content': []}, script_nonce=False, style_nonce=False, report_only=False) +# app.add_middleware(XContentTypeOptions) +# app.add_middleware(XFrame, Option={'X-Frame-Options': 'DENY'}) app.add_middleware( CORSMiddleware, diff --git a/backend/src/main.py b/backend/src/main.py index eebdff70f..7bf7c17bd 100644 --- a/backend/src/main.py +++ b/backend/src/main.py @@ -144,23 +144,33 @@ def create_source_node_graph_url_youtube(graph, model, source_url, source_type): logging.info(f"match value: {match}") cred_path = os.path.join(os.getcwd(),"llm-experiments_credentials.json") print(f'Credential file path {cred_path}') + if os.path.exists(cred_path): + logging.info("File path exist") + with open(cred_path,'r') as secret_file: + secret_data = json.load(secret_file) + logging.info(f"Project id : {secret_data['project_id']}") + logging.info(f"Universal domain: {secret_data['universe_domain']}") + else: + logging.warning("credntial file path not exist") + video_id = parse_qs(urlparse(youtube_url).query).get('v') print(f'Video Id Youtube: {video_id}') - # google_api_client = GoogleApiClient(service_account_path=Path(cred_path)) - # youtube_loader_channel = GoogleApiYoutubeLoader( - # google_api_client=google_api_client, - # video_ids=[video_id[0].strip()], add_video_info=True - # ) - # youtube_transcript = youtube_loader_channel.load() - + google_api_client = GoogleApiClient(service_account_path=Path(cred_path)) + youtube_loader_channel = GoogleApiYoutubeLoader( + google_api_client=google_api_client, + video_ids=[video_id[0].strip()], add_video_info=True + ) + youtube_transcript = youtube_loader_channel.load() + page_content = youtube_transcript[0].page_content + obj_source_node.file_name = match.group(1)#youtube_transcript[0].metadata["snippet"]["title"] - transcript= get_youtube_combined_transcript(match.group(1)) + # transcript= get_youtube_combined_transcript(match.group(1)) # print(transcript) - if transcript==None or len(transcript)==0: + if page_content==None or len(page_content)==0: message = f"Youtube transcript is not available for : {obj_source_node.file_name}" raise Exception(message) else: - obj_source_node.file_size = sys.getsizeof(transcript) + obj_source_node.file_size = sys.getsizeof(page_content) graphDb_data_Access = graphDBdataAccess(graph) graphDb_data_Access.create_source_node(obj_source_node) From 060fd2d15c7111dc1281fb90db94fd9904b154ec Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Fri, 20 Sep 2024 11:39:19 +0530 Subject: [PATCH 113/292] Communities (#721) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * added communities creation * added communities * removed tqdm * removed __Entity__ labels * removed graph_object * removed graph object in the function * Modified queries * added properties and modified to entity labels * Post processing call after all files completion (#716) * Dev To STAGING (#532) * format fixes and graph schema indication fix * Update README.md * added chat modes variable in env updated the readme * spell fix * added the chat mode in env table * added the logos * fixed the overflow issues * removed the extra fix * Fixed specific scenario "when the text from schema closes it should reopen the previous modal" * readme changes * removed dev console logs * added new retrieval query (#533) * format fixes and tab rendering fix * fixed the setting modal reopen issue --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Dev (#535) * format fixes and graph schema indication fix * Update README.md * added chat modes variable in env updated the readme * spell fix * added the chat mode in env table * added the logos * fixed the overflow issues * removed the extra fix * Fixed specific scenario "when the text from schema closes it should reopen the previous modal" * readme changes * removed dev console logs * added new retrieval query (#533) * format fixes and tab rendering fix * fixed the setting modal reopen issue --------- Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Dev (#537) * format fixes and graph schema indication fix * Update README.md * added chat modes variable in env updated the readme * spell fix * added the chat mode in env table * added the logos * fixed the overflow issues * removed the extra fix * Fixed specific scenario "when the text from schema closes it should reopen the previous modal" * readme changes * removed dev console logs * added new retrieval query (#533) * format fixes and tab rendering fix * fixed the setting modal reopen issue --------- Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Fix typo: correct 'josn_obj' to 'json_obj' (#697) * Staging To Main (#495) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * Dev (#433) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env * DEV to STAGING (#461) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * DEV to STAGING (#462) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * added upload api * changed the dropzone error message * Dev to staging (#466) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env * added upload api * changed the dropzone error message --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani… * modified the summary creation * fixed the summary creation * refactored qa integration * modified the chat mode settings * renamed QA_integration * added graphdatascience * moved settings to constants * modified constants * Science Molecule & database icon addition (#722) * DataScience icon addition * added gds status to connect call * icon stroke changes --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Add communities check and show respective chat modes (#729) * DataScience icon addition * added checkbox to create_communities * added conditionall check for community chat modes --------- Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> * added local search * 725 add checkbox for create communities (#728) * DataScience icon addition * added checkbox to create_communities * added gds status to connect call * added conditionall check for community chat modes * icon stroke changes * isgds active check * icon changes * isGdsVal change * format fixes * checkbox check uncheck change * graph query --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * modified local search query * added entity details for chat * modified chunkids * modified chunk_entities * Add communities Checkbox to graph viz (#739) * DataScience icon addition * added checkbox to create_communities * added gds status to connect call * added conditionall check for community chat modes * icon stroke changes * isgds active check * icon changes * isGdsVal change * format fixes * checkbox check uncheck change * graph query * checkbox addition * filter logic * filter logic missing checks * updated_graph_query * filter logic optimised * gds active check * handle checkbox show --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * changed name * modified the query * updated entities param * added document to details * added global embedding * added database * added database * modified is_entity * modifies chunk entities * removed QA integration * created neo4j from existing index * Integrate local search to chat details (#746) * added the commuties tab * removed unused variables * removed scipy libarary * added the mode check * Integrated the communities tab * added the cjheck * enabled the top entities mode * tabs order rearange * added the loader to sources tab for entity search+vector * fixed the chat mode per prop --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed entity label * Added Description to chat mode menu (#743) * added tooltips to chat mode menu * addition of description to menu * 741-tooltips-to-selectOptions * menu changes * acommunities name change * close changes * name changes * format fixes * community check * Entity Empty Label fix and Icon * Update Utils.ts * removed __Entity__ labels * spell fix * fixed postprocessing method invoking issue for odd no files * lint fix * Added filesource and name in chunks * Graph communities (#748) * UI changes * modes enable disable * separated sources entities chunk communities * communities added into separate component * Update ChatInfoModal.tsx * added filename and source for chunksinfo * removed the console.log * mode disable changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * aria label addition * code improvements used URL class for host url check * host level check * encryption of localstorage values * 'mode-selection-changes' * added neo4j from existing index to entity vector mode * label changes --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: destiny966113 <90891243+destiny966113@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> Co-authored-by: Ikko Eltociear Ashimine Co-authored-by: Pravesh1988 Co-authored-by: edenbuaa --- backend/requirements.txt | 5 +- backend/score.py | 24 +- backend/src/QA_integration.py | 797 ++-- backend/src/QA_integration_new.py | 424 -- backend/src/QA_optimization.py | 217 - backend/src/chunkid_entities.py | 137 +- backend/src/communities.py | 408 ++ backend/src/graphDB_dataAccess.py | 32 +- backend/src/graph_query.py | 19 +- backend/src/llm.py | 2 + backend/src/main.py | 1 - backend/src/make_relationships.py | 7 +- backend/src/post_processing.py | 4 +- backend/src/shared/common_fn.py | 4 +- backend/src/shared/constants.py | 239 +- experiments/graphrag.ipynb | 3519 +++++++++++++++++ frontend/src/App.css | 26 +- .../src/components/ChatBot/ChatInfoModal.tsx | 400 +- .../src/components/ChatBot/ChatModeToggle.tsx | 106 +- frontend/src/components/ChatBot/Chatbot.tsx | 16 +- frontend/src/components/ChatBot/ChunkInfo.tsx | 125 + .../src/components/ChatBot/Communities.tsx | 36 + .../src/components/ChatBot/EntitiesInfo.tsx | 91 + .../ChatBot/ExpandedChatButtonContainer.tsx | 2 +- .../src/components/ChatBot/Info/InfoModal.tsx | 361 -- .../src/components/ChatBot/SourcesInfo.tsx | 137 + frontend/src/components/Content.tsx | 46 +- .../components/DataSources/Local/DropZone.tsx | 2 +- .../Local/DropZoneForSmallLayouts.tsx | 3 +- frontend/src/components/FileTable.tsx | 2 +- .../components/Graph/CheckboxSelection.tsx | 16 +- .../src/components/Graph/GraphViewModal.tsx | 70 +- frontend/src/components/Graph/LegendsChip.tsx | 11 +- frontend/src/components/Layout/Header.tsx | 2 +- frontend/src/components/Layout/SideNav.tsx | 4 +- .../ConnectionModal/ConnectionModal.tsx | 11 +- .../PostProcessingCheckList/index.tsx | 56 +- .../Popups/Settings/SchemaFromText.tsx | 1 - frontend/src/components/UI/DatabaseIcon.tsx | 25 + .../src/components/UI/DatabaseStatusIcon.tsx | 26 + .../src/components/UI/IconButtonToolTip.tsx | 27 +- frontend/src/components/UI/Menu.tsx | 31 +- .../src/components/UI/ScienceMolecule.tsx | 40 + .../WebSources/GenericSourceButton.tsx | 2 +- frontend/src/context/UserCredentials.tsx | 6 + frontend/src/context/UsersFiles.tsx | 5 +- frontend/src/services/CancelAPI.ts | 2 +- frontend/src/services/ChunkEntitiesInfo.ts | 9 +- frontend/src/types.ts | 47 +- frontend/src/utils/Constants.ts | 79 +- frontend/src/utils/Utils.ts | 196 +- 51 files changed, 5956 insertions(+), 1902 deletions(-) delete mode 100644 backend/src/QA_integration_new.py delete mode 100644 backend/src/QA_optimization.py create mode 100644 backend/src/communities.py create mode 100644 experiments/graphrag.ipynb create mode 100644 frontend/src/components/ChatBot/ChunkInfo.tsx create mode 100644 frontend/src/components/ChatBot/Communities.tsx create mode 100644 frontend/src/components/ChatBot/EntitiesInfo.tsx delete mode 100644 frontend/src/components/ChatBot/Info/InfoModal.tsx create mode 100644 frontend/src/components/ChatBot/SourcesInfo.tsx create mode 100644 frontend/src/components/UI/DatabaseIcon.tsx create mode 100644 frontend/src/components/UI/DatabaseStatusIcon.tsx create mode 100644 frontend/src/components/UI/ScienceMolecule.tsx diff --git a/backend/requirements.txt b/backend/requirements.txt index 7c67f13fa..158458ce1 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -140,7 +140,6 @@ requests==2.32.3 rsa==4.9 s3transfer==0.10.1 safetensors==0.4.1 -scipy==1.10.1 shapely==2.0.3 six==1.16.0 sniffio==1.3.1 @@ -179,4 +178,6 @@ sentence-transformers==3.0.1 google-cloud-logging==3.10.0 PyMuPDF==1.24.5 pypandoc==1.13 -Secweb==1.11.0 \ No newline at end of file +graphdatascience==1.10 +Secweb==1.11.0 + diff --git a/backend/score.py b/backend/score.py index 891444e62..e87fc618e 100644 --- a/backend/score.py +++ b/backend/score.py @@ -2,7 +2,7 @@ from fastapi_health import health from fastapi.middleware.cors import CORSMiddleware from src.main import * -from src.QA_integration_new import * +from src.QA_integration import * from src.entities.user_credential import user_credential from src.shared.common_fn import * import uvicorn @@ -16,6 +16,7 @@ from src.chunkid_entities import get_entities_from_chunkids from src.post_processing import create_fulltext, create_entity_embedding from sse_starlette.sse import EventSourceResponse +from src.communities import create_communities import json from typing import List, Mapping from starlette.middleware.sessions import SessionMiddleware @@ -47,11 +48,6 @@ def sick(): return False app = FastAPI() -SecWeb(app=app, Option={'referrer': False, 'xframe': False}) -# app.add_middleware(HSTS, Option={'max-age': 4}) -# app.add_middleware(ContentSecurityPolicy, Option={'default-src': ["'self'"], 'base-uri': ["'self'"], 'block-all-mixed-content': []}, script_nonce=False, style_nonce=False, report_only=False) -# app.add_middleware(XContentTypeOptions) -# app.add_middleware(XFrame, Option={'X-Frame-Options': 'DENY'}) app.add_middleware( CORSMiddleware, @@ -268,8 +264,12 @@ async def post_processing(uri=Form(), userName=Form(), password=Form(), database await asyncio.to_thread(create_entity_embedding, graph) json_obj = {'api_name': 'post_processing/create_entity_embedding', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} logging.info(f'Entity Embeddings created') - - logger.log_struct(json_obj, "INFO") + if "create_communities" in tasks: + model = "openai-gpt-4o" + await asyncio.to_thread(create_communities, uri, userName, password, database,model) + josn_obj = {'api_name': 'post_processing/create_communities', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(josn_obj) + logging.info(f'created communities') return create_api_response('Success', message='All tasks completed successfully') except Exception as e: @@ -311,10 +311,10 @@ async def chat_bot(uri=Form(),model=Form(None),userName=Form(), password=Form(), gc.collect() @app.post("/chunk_entities") -async def chunk_entities(uri=Form(),userName=Form(), password=Form(), chunk_ids=Form(None)): +async def chunk_entities(uri=Form(),userName=Form(), password=Form(), database=Form(), chunk_ids=Form(None),is_entity=Form()): try: logging.info(f"URI: {uri}, Username: {userName}, chunk_ids: {chunk_ids}") - result = await asyncio.to_thread(get_entities_from_chunkids,uri=uri, username=userName, password=password, chunk_ids=chunk_ids) + result = await asyncio.to_thread(get_entities_from_chunkids,uri=uri, username=userName, password=password, database=database,chunk_ids=chunk_ids,is_entity=json.loads(is_entity.lower())) json_obj = {'api_name':'chunk_entities','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} logger.log_struct(json_obj, "INFO") return create_api_response('Success',data=result) @@ -330,6 +330,7 @@ async def chunk_entities(uri=Form(),userName=Form(), password=Form(), chunk_ids= @app.post("/graph_query") async def graph_query( uri: str = Form(), + database: str = Form(), userName: str = Form(), password: str = Form(), document_names: str = Form(None), @@ -341,6 +342,7 @@ async def graph_query( uri=uri, username=userName, password=password, + database=database, document_names=document_names ) json_obj = {'api_name':'graph_query','db_url':uri,'document_names':document_names, 'logging_time': formatted_time(datetime.now(timezone.utc))} @@ -451,7 +453,7 @@ async def generate(): graph = create_graph_database_connection(uri, userName, decoded_password, database) graphDb_data_Access = graphDBdataAccess(graph) result = graphDb_data_Access.get_current_status_document_node(file_name) - print(f'Result of document status in SSE : {result}') + # print(f'Result of document status in SSE : {result}') if len(result) > 0: status = json.dumps({'fileName':file_name, 'status':result[0]['Status'], diff --git a/backend/src/QA_integration.py b/backend/src/QA_integration.py index 6a70c3ec0..7ac99f66b 100644 --- a/backend/src/QA_integration.py +++ b/backend/src/QA_integration.py @@ -1,342 +1,585 @@ -from langchain_community.vectorstores.neo4j_vector import Neo4jVector -from langchain.chains import GraphCypherQAChain -from langchain.graphs import Neo4jGraph import os +import json +from datetime import datetime +import time +from typing import Any from dotenv import load_dotenv -from langchain.chains import RetrievalQA -from langchain.chains import RetrievalQAWithSourcesChain -from langchain_openai import ChatOpenAI -from langchain_openai import OpenAIEmbeddings -from langchain_google_vertexai import VertexAIEmbeddings -from langchain_google_vertexai import ChatVertexAI -from langchain_google_vertexai import HarmBlockThreshold, HarmCategory import logging + +# LangChain imports +from langchain_community.vectorstores.neo4j_vector import Neo4jVector from langchain_community.chat_message_histories import Neo4jChatMessageHistory -from langchain_community.embeddings.sentence_transformer import SentenceTransformerEmbeddings -from src.shared.common_fn import load_embedding_model -import re -from typing import Any -from datetime import datetime -import time +from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder +from langchain_core.output_parsers import StrOutputParser +from langchain_core.runnables import RunnableBranch +from langchain.retrievers import ContextualCompressionRetriever +from langchain_community.document_transformers import EmbeddingsRedundantFilter +from langchain.retrievers.document_compressors import EmbeddingsFilter, DocumentCompressorPipeline +from langchain_text_splitters import TokenTextSplitter +from langchain_core.messages import HumanMessage, AIMessage +from langchain.chains import GraphCypherQAChain -load_dotenv() +# LangChain chat models +from langchain_openai import ChatOpenAI, AzureChatOpenAI +from langchain_google_vertexai import ChatVertexAI +from langchain_groq import ChatGroq +from langchain_anthropic import ChatAnthropic +from langchain_fireworks import ChatFireworks +from langchain_aws import ChatBedrock +from langchain_community.chat_models import ChatOllama + +# Local imports +from src.llm import get_llm +from src.shared.common_fn import load_embedding_model +from src.shared.constants import * -openai_api_key = os.environ.get('OPENAI_API_KEY') +load_dotenv() EMBEDDING_MODEL = os.getenv('EMBEDDING_MODEL') EMBEDDING_FUNCTION , _ = load_embedding_model(EMBEDDING_MODEL) -CHAT_MAX_TOKENS = 1000 - - -# RETRIEVAL_QUERY = """ -# WITH node, score, apoc.text.join([ (node)-[:__HAS_ENTITY__]->(e) | head(labels(e)) + ": "+ e.id],", ") as entities -# MATCH (node)-[:__PART_OF__]->(d:Document) -# WITH d, apoc.text.join(collect(node.text + "\n" + entities),"\n----\n") as text, avg(score) as score -# RETURN text, score, {source: COALESCE(CASE WHEN d.url CONTAINS "None" THEN d.fileName ELSE d.url END, d.fileName)} as metadata -# """ - -RETRIEVAL_QUERY = """ -WITH node as chunk, score -MATCH (chunk)-[:__PART_OF__]->(d:__Document__) -CALL { WITH chunk -MATCH (chunk)-[:__HAS_ENTITY__]->(e) -MATCH path=(e)(()-[rels:!__HAS_ENTITY__&!__PART_OF__]-()){0,3}(:!__Chunk__&!__Document__) -UNWIND rels as r -RETURN collect(distinct r) as rels -} -WITH d, collect(distinct chunk) as chunks, avg(score) as score, apoc.coll.toSet(apoc.coll.flatten(collect(rels))) as rels -WITH d, score, -[c in chunks | c.text] as texts, -[r in rels | coalesce(apoc.coll.removeAll(labels(startNode(r)),['__Entity__'])[0],"") +":"+ startNode(r).id + " "+ type(r) + " " + coalesce(apoc.coll.removeAll(labels(endNode(r)),['__Entity__'])[0],"") +":" + endNode(r).id] as entities -WITH d, score, -apoc.text.join(texts,"\n----\n") + -apoc.text.join(entities,"\n") -as text, entities -RETURN text, score, {source: COALESCE(CASE WHEN d.url CONTAINS "None" THEN d.fileName ELSE d.url END, d.fileName), entities:entities} as metadata -""" - -FINAL_PROMPT = """ -You are an AI-powered question-answering agent tasked with providing accurate and direct responses to user queries. Utilize information from the chat history, current user input, and Relevant Information effectively. - -Response Requirements: -- Deliver concise and direct answers to the user's query without headers unless requested. -- Acknowledge and utilize relevant previous interactions based on the chat history summary. -- Respond to initial greetings appropriately, but avoid including a greeting in subsequent responses unless the chat is restarted or significantly paused. -- For non-general questions, strive to provide answers using chat history and Relevant Information ONLY do not Hallucinate. -- Clearly state if an answer is unknown; avoid speculating. - -Instructions: -- Prioritize directly answering the User Input: {question}. -- Use the Chat History Summary: {chat_summary} to provide context-aware responses. -- Refer to Relevant Information: {vector_result} only if it directly relates to the query. -- Cite sources clearly when using Relevant Information in your response [Sources: {sources}] without fail. The Source must be printed only at the last in the format [Source: source1,source2] . Duplicate sources should be removed. -Ensure that answers are straightforward and context-aware, focusing on being relevant and concise. -""" - -def get_llm(model: str,max_tokens=1000) -> Any: - """Retrieve the specified language model based on the model name.""" - - model_versions = { - "openai-gpt-3.5": "gpt-3.5-turbo-16k", - "gemini-1.0-pro": "gemini-1.0-pro-001", - "gemini-1.5-pro": "gemini-1.5-pro-preview-0409", - "openai-gpt-4": "gpt-4-0125-preview", - "diffbot" : "gpt-4-0125-preview", - "openai-gpt-4o":"gpt-4o", - "openai-gpt-4o-mini": "gpt-4o-mini", - } - if model in model_versions: - model_version = model_versions[model] - logging.info(f"Chat Model: {model}, Model Version: {model_version}") + +def get_total_tokens(ai_response, llm): + try: + if isinstance(llm, (ChatOpenAI, AzureChatOpenAI, ChatFireworks, ChatGroq)): + total_tokens = ai_response.response_metadata.get('token_usage', {}).get('total_tokens', 0) + + elif isinstance(llm, ChatVertexAI): + total_tokens = ai_response.response_metadata.get('usage_metadata', {}).get('prompt_token_count', 0) + + elif isinstance(llm, ChatBedrock): + total_tokens = ai_response.response_metadata.get('usage', {}).get('total_tokens', 0) + + elif isinstance(llm, ChatAnthropic): + input_tokens = int(ai_response.response_metadata.get('usage', {}).get('input_tokens', 0)) + output_tokens = int(ai_response.response_metadata.get('usage', {}).get('output_tokens', 0)) + total_tokens = input_tokens + output_tokens + + elif isinstance(llm, ChatOllama): + total_tokens = ai_response.response_metadata.get("prompt_eval_count", 0) - if "Gemini" in model: - llm = ChatVertexAI( - model_name=model_version, - convert_system_message_to_human=True, - max_tokens=max_tokens, - temperature=0, - safety_settings={ - HarmCategory.HARM_CATEGORY_UNSPECIFIED: HarmBlockThreshold.BLOCK_NONE, - HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: HarmBlockThreshold.BLOCK_NONE, - HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_NONE, - HarmCategory.HARM_CATEGORY_HARASSMENT: HarmBlockThreshold.BLOCK_NONE, - HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: HarmBlockThreshold.BLOCK_NONE - } - ) else: - llm = ChatOpenAI(model=model_version, temperature=0,max_tokens=max_tokens) + logging.warning(f"Unrecognized language model: {type(llm)}. Returning 0 tokens.") + total_tokens = 0 - return llm,model_version + except Exception as e: + logging.error(f"Error retrieving total tokens: {e}") + total_tokens = 0 - else: - logging.error(f"Unsupported model: {model}") - return None,None + return total_tokens + +def clear_chat_history(graph, session_id): + try: + history = Neo4jChatMessageHistory( + graph=graph, + session_id=session_id + ) + + history.clear() + + return { + "session_id": session_id, + "message": "The chat history has been cleared.", + "user": "chatbot" + } + + except Exception as e: + logging.error(f"Error clearing chat history for session {session_id}: {e}") + return { + "session_id": session_id, + "message": "Failed to clear chat history.", + "user": "chatbot" + } + +def get_sources_and_chunks(sources_used, docs): + chunkdetails_list = [] + sources_used_set = set(sources_used) + seen_ids_and_scores = set() + + for doc in docs: + try: + source = doc.metadata.get("source") + chunkdetails = doc.metadata.get("chunkdetails", []) + + if source in sources_used_set: + for chunkdetail in chunkdetails: + id = chunkdetail.get("id") + score = round(chunkdetail.get("score", 0), 4) -def vector_embed_results(qa,question): - vector_res={} + id_and_score = (id, score) + + if id_and_score not in seen_ids_and_scores: + seen_ids_and_scores.add(id_and_score) + chunkdetails_list.append({**chunkdetail, "score": score}) + + except Exception as e: + logging.error(f"Error processing document: {e}") + + result = { + 'sources': sources_used, + 'chunkdetails': chunkdetails_list, + "entities" : list() + } + return result + +def get_rag_chain(llm, system_template=CHAT_SYSTEM_TEMPLATE): try: - result = qa({"query": question}) - vector_res['result']=result.get("result") - - sources = set() - entities = set() - for document in result["source_documents"]: - sources.add(document.metadata["source"]) - for entiti in document.metadata["entities"]: - entities.add(entiti) - vector_res['source']=list(sources) - vector_res['entities'] = list(entities) - if len( vector_res['entities']) > 5: - vector_res['entities'] = vector_res['entities'][:5] - - # list_source_docs=[] - # for i in result["source_documents"]: - # list_source_docs.append(i.metadata['source']) - # vector_res['source']=list_source_docs - - # result = qa({"question":question},return_only_outputs=True) - # vector_res['result'] = result.get("answer") - # vector_res["source"] = result.get("sources") + question_answering_prompt = ChatPromptTemplate.from_messages( + [ + ("system", system_template), + MessagesPlaceholder(variable_name="messages"), + ( + "human", + "User question: {input}" + ), + ] + ) + + question_answering_chain = question_answering_prompt | llm + + return question_answering_chain + except Exception as e: - error_message = str(e) - logging.exception(f'Exception in vector embedding in QA component:{error_message}') - # raise Exception(error_message) + logging.error(f"Error creating RAG chain: {e}") + raise + +def format_documents(documents, model): + prompt_token_cutoff = 4 + for model_names, value in CHAT_TOKEN_CUT_OFF.items(): + if model in model_names: + prompt_token_cutoff = value + break + + sorted_documents = sorted(documents, key=lambda doc: doc.state.get("query_similarity_score", 0), reverse=True) + sorted_documents = sorted_documents[:prompt_token_cutoff] + + formatted_docs = [] + sources = set() + lc_entities = {'entities':list()} + + for doc in sorted_documents: + try: + source = doc.metadata.get('source', "unknown") + sources.add(source) + + lc_entities = doc.metadata if 'entities'in doc.metadata.keys() else lc_entities + + formatted_doc = ( + "Document start\n" + f"This Document belongs to the source {source}\n" + f"Content: {doc.page_content}\n" + "Document end\n" + ) + formatted_docs.append(formatted_doc) + + except Exception as e: + logging.error(f"Error formatting document: {e}") - return vector_res + return "\n\n".join(formatted_docs), sources,lc_entities + +def process_documents(docs, question, messages, llm, model,chat_mode_settings): + start_time = time.time() -def save_chat_history(history,user_message,ai_message): try: - # history = Neo4jChatMessageHistory( - # graph=graph, - # session_id=session_id - # ) - history.add_user_message(user_message) - history.add_ai_message(ai_message) - logging.info(f'Successfully saved chat history') + formatted_docs, sources,lc_entities = format_documents(docs, model) + + rag_chain = get_rag_chain(llm=llm) + + ai_response = rag_chain.invoke({ + "messages": messages[:-1], + "context": formatted_docs, + "input": question + }) + if chat_mode_settings["mode"] == "entity search+vector": + result = {'sources': list(), + 'chunkdetails': list()} + result.update(lc_entities) + else: + result = get_sources_and_chunks(sources, docs) + content = ai_response.content + total_tokens = get_total_tokens(ai_response, llm) + + predict_time = time.time() - start_time + logging.info(f"Final response predicted in {predict_time:.2f} seconds") + except Exception as e: - error_message = str(e) - logging.exception(f'Exception in saving chat history:{error_message}') + logging.error(f"Error processing documents: {e}") + raise -def get_chat_history(llm, history): - """Retrieves and summarizes the chat history for a given session.""" + return content, result, total_tokens + +def retrieve_documents(doc_retriever, messages): + start_time = time.time() try: - # history = Neo4jChatMessageHistory( - # graph=graph, - # session_id=session_id - # ) - chat_history = history.messages + docs = doc_retriever.invoke({"messages": messages}) + doc_retrieval_time = time.time() - start_time + logging.info(f"Documents retrieved in {doc_retrieval_time:.2f} seconds") - if not chat_history: - return "" + except Exception as e: + logging.error(f"Error retrieving documents: {e}") + raise + + return docs - if len(chat_history) > 4: - chat_history = chat_history[-4:] +def create_document_retriever_chain(llm, retriever): + try: + logging.info("Starting to create document retriever chain") - condense_template = f""" - Given the following earlier conversation, summarize the chat history. - Make sure to include all relevant information. - Chat History: {chat_history} - """ - chat_summary = llm.predict(condense_template) - return chat_summary + query_transform_prompt = ChatPromptTemplate.from_messages( + [ + ("system", QUESTION_TRANSFORM_TEMPLATE), + MessagesPlaceholder(variable_name="messages") + ] + ) - except Exception as e: - logging.exception(f"Exception in retrieving chat history: {e}") - return "" + output_parser = StrOutputParser() -def clear_chat_history(graph, session_id): + splitter = TokenTextSplitter(chunk_size=CHAT_DOC_SPLIT_SIZE, chunk_overlap=0) + embeddings_filter = EmbeddingsFilter( + embeddings=EMBEDDING_FUNCTION, + similarity_threshold=CHAT_EMBEDDING_FILTER_SCORE_THRESHOLD + ) + + pipeline_compressor = DocumentCompressorPipeline( + transformers=[splitter, embeddings_filter] + ) + + compression_retriever = ContextualCompressionRetriever( + base_compressor=pipeline_compressor, base_retriever=retriever + ) + + query_transforming_retriever_chain = RunnableBranch( + ( + lambda x: len(x.get("messages", [])) == 1, + (lambda x: x["messages"][-1].content) | compression_retriever, + ), + query_transform_prompt | llm | output_parser | compression_retriever, + ).with_config(run_name="chat_retriever_chain") + logging.info("Successfully created document retriever chain") + return query_transforming_retriever_chain + + except Exception as e: + logging.error(f"Error creating document retriever chain: {e}", exc_info=True) + raise + +def initialize_neo4j_vector(graph, chat_mode_settings): try: - logging.info(f"Clearing chat history for session ID: {session_id}") - history = Neo4jChatMessageHistory( - graph=graph, - session_id=session_id + mode = chat_mode_settings.get('mode', 'undefined') + retrieval_query = chat_mode_settings.get("retrieval_query") + index_name = chat_mode_settings.get("index_name") + keyword_index = chat_mode_settings.get("keyword_index", "") + + if not retrieval_query or not index_name: + raise ValueError("Required settings 'retrieval_query' or 'index_name' are missing.") + + if keyword_index: + neo_db = Neo4jVector.from_existing_graph( + embedding=EMBEDDING_FUNCTION, + index_name=index_name, + retrieval_query=retrieval_query, + graph=graph, + search_type="hybrid", + node_label="Chunk", + embedding_node_property="embedding", + text_node_properties=["text"], + keyword_index_name=keyword_index + ) + logging.info(f"Successfully retrieved Neo4jVector Fulltext index '{index_name}' and keyword index '{keyword_index}'") + elif mode == "entity search+vector": + neo_db = Neo4jVector.from_existing_index( + embedding=EMBEDDING_FUNCTION, + index_name=index_name, + retrieval_query=retrieval_query, + graph=graph + ) + else: + neo_db = Neo4jVector.from_existing_graph( + embedding=EMBEDDING_FUNCTION, + index_name=index_name, + retrieval_query=retrieval_query, + graph=graph, + node_label="Chunk", + embedding_node_property="embedding", + text_node_properties=["text"] + ) + logging.info(f"Successfully retrieved Neo4jVector index '{index_name}'") + except Exception as e: + index_name = chat_mode_settings.get("index_name") + logging.error(f"Error retrieving Neo4jVector index {index_name} : {e}") + raise + return neo_db + +def create_retriever(neo_db, document_names, chat_mode_settings,search_k, score_threshold): + if document_names and chat_mode_settings["document_filter"]: + retriever = neo_db.as_retriever( + search_type="similarity_score_threshold", + search_kwargs={ + 'k': search_k, + 'score_threshold': score_threshold, + 'filter': {'fileName': {'$in': document_names}} + } ) - history.clear() - logging.info("Chat history cleared successfully") + logging.info(f"Successfully created retriever with search_k={search_k}, score_threshold={score_threshold} for documents {document_names}") + else: + retriever = neo_db.as_retriever( + search_type="similarity_score_threshold", + search_kwargs={'k': search_k, 'score_threshold': score_threshold} + ) + logging.info(f"Successfully created retriever with search_k={search_k}, score_threshold={score_threshold}") + return retriever +def get_neo4j_retriever(graph, document_names,chat_mode_settings, search_k=CHAT_SEARCH_KWARG_K, score_threshold=CHAT_SEARCH_KWARG_SCORE_THRESHOLD): + try: + + neo_db = initialize_neo4j_vector(graph, chat_mode_settings) + document_names= list(map(str.strip, json.loads(document_names))) + search_k = LOCAL_COMMUNITY_TOP_K if chat_mode_settings["mode"] == "entity search+vector" else CHAT_SEARCH_KWARG_K + retriever = create_retriever(neo_db, document_names,chat_mode_settings, search_k, score_threshold) + return retriever + except Exception as e: + index_name = chat_mode_settings.get("index_name") + logging.error(f"Error retrieving Neo4jVector index {index_name} or creating retriever: {e}") + raise Exception(f"An error occurred while retrieving the Neo4jVector index or creating the retriever. Please drop and create a new vector index '{index_name}': {e}") from e + + +def setup_chat(model, graph, document_names, chat_mode_settings): + start_time = time.time() + try: + model = "openai-gpt-4o" if model == "diffbot" else model + + llm, model_name = get_llm(model=model) + logging.info(f"Model called in chat: {model} (version: {model_name})") + + retriever = get_neo4j_retriever(graph=graph, chat_mode_settings=chat_mode_settings, document_names=document_names) + doc_retriever = create_document_retriever_chain(llm, retriever) + + chat_setup_time = time.time() - start_time + logging.info(f"Chat setup completed in {chat_setup_time:.2f} seconds") + + except Exception as e: + logging.error(f"Error during chat setup: {e}", exc_info=True) + raise + + return llm, doc_retriever, model_name + +def process_chat_response(messages,history, question, model, graph, document_names,chat_mode_settings): + try: + llm, doc_retriever, model_version = setup_chat(model, graph, document_names,chat_mode_settings) + + docs = retrieve_documents(doc_retriever, messages) + if docs: + content, result, total_tokens = process_documents(docs, question, messages, llm, model,chat_mode_settings) + else: + content = "I couldn't find any relevant documents to answer your question." + result = {"sources": [], "chunkdetails": [],"entities":[]} + total_tokens = 0 + + ai_response = AIMessage(content=content) + messages.append(ai_response) + summarize_and_log(history, messages, llm) + return { - "session_id": session_id, - "message": "The chat history is cleared", + "session_id": "", + "message": content, + "info": { + "sources": result["sources"], + "model": model_version, + "chunkdetails": result["chunkdetails"], + "total_tokens": total_tokens, + "response_time": 0, + "mode": chat_mode_settings["mode"], + "entities" : result["entities"] + }, "user": "chatbot" } + except Exception as e: - logging.exception(f"Error occurred while clearing chat history for session ID {session_id}: {e}") - - -def extract_and_remove_source(message): - pattern = r'\[Source: ([^\]]+)\]' - match = re.search(pattern, message) - if match: - sources_string = match.group(1) - sources = [source.strip().strip("'") for source in sources_string.split(',')] - new_message = re.sub(pattern, '', message).strip() - response = { - "message" : new_message, - "sources" : sources - } - else: - response = { - "message" : message, - "sources" : [] - } - return response - -def clear_chat_history(graph,session_id): - history = Neo4jChatMessageHistory( - graph=graph, - session_id=session_id - ) - history.clear() - return { - "session_id": session_id, - "message": "The chat History is cleared", + logging.exception(f"Error processing chat response at {datetime.now()}: {str(e)}") + return { + "session_id": "", + "message": "Something went wrong", + "info": { + "sources": [], + "chunkdetails": [], + "total_tokens": 0, + "response_time": 0, + "error": f"{type(e).__name__}: {str(e)}", + "mode": chat_mode_settings["mode"], + "entities": [] + }, "user": "chatbot" - } - -def QA_RAG(graph,model,question,session_id): - logging.info(f"QA_RAG called at {datetime.now()}") - # model = "Gemini Pro" - try: - qa_rag_start_time = time.time() + } +def summarize_and_log(history, stored_messages, llm): + if not stored_messages: + logging.info("No messages to summarize.") + return False + try: start_time = time.time() - neo_db = Neo4jVector.from_existing_index( - embedding=EMBEDDING_FUNCTION, - index_name="vector", - retrieval_query=RETRIEVAL_QUERY, - graph=graph + + summarization_prompt = ChatPromptTemplate.from_messages( + [ + MessagesPlaceholder(variable_name="chat_history"), + ( + "human", + "Summarize the above chat messages into a concise message, focusing on key points and relevant details that could be useful for future conversations. Exclude all introductions and extraneous information." + ), + ] ) + summarization_chain = summarization_prompt | llm - history = Neo4jChatMessageHistory( + summary_message = summarization_chain.invoke({"chat_history": stored_messages}) + + history.clear() + history.add_user_message("Our current conversation summary till now") + history.add_message(summary_message) + + history_summarized_time = time.time() - start_time + logging.info(f"Chat History summarized in {history_summarized_time:.2f} seconds") + + return True + + except Exception as e: + logging.error(f"An error occurred while summarizing messages: {e}") + return False + +def create_graph_chain(model, graph): + try: + logging.info(f"Graph QA Chain using LLM model: {model}") + + cypher_llm,model_name = get_llm(model) + qa_llm,model_name = get_llm(model) + graph_chain = GraphCypherQAChain.from_llm( + cypher_llm=cypher_llm, + qa_llm=qa_llm, + validate_cypher= True, graph=graph, - session_id=session_id + # verbose=True, + return_intermediate_steps = True, + top_k=3 ) - - llm,model_version = get_llm(model=model,max_tokens=CHAT_MAX_TOKENS) - qa = RetrievalQA.from_chain_type( - llm=llm, - chain_type="stuff", - retriever=neo_db.as_retriever(search_kwargs={'k': 3, "score_threshold": 0.7}), - return_source_documents=True - ) - # qa = RetrievalQAWithSourcesChain.from_chain_type( - # llm=llm, - # chain_type="stuff", - # retriever=neo_db.as_retriever(search_kwargs={'k': 3, "score_threshold": 0.7})) + logging.info("GraphCypherQAChain instance created successfully.") + return graph_chain,qa_llm,model_name - db_setup_time = time.time() - start_time - logging.info(f"DB Setup completed in {db_setup_time:.2f} seconds") - - start_time = time.time() - chat_summary = get_chat_history(llm,history) - chat_history_time = time.time() - start_time - logging.info(f"Chat history summarized in {chat_history_time:.2f} seconds") - # print(chat_summary) + except Exception as e: + logging.error(f"An error occurred while creating the GraphCypherQAChain instance. : {e}") - start_time = time.time() - vector_res = vector_embed_results(qa, question) - vector_time = time.time() - start_time - logging.info(f"Vector response obtained in {vector_time:.2f} seconds") - # print(vector_res) +def get_graph_response(graph_chain, question): + try: + cypher_res = graph_chain.invoke({"query": question}) - formatted_prompt = FINAL_PROMPT.format( - question=question, - chat_summary=chat_summary, - vector_result=vector_res.get('result', ''), - sources=vector_res.get('source', '') - ) - # print(formatted_prompt) - - start_time = time.time() - # llm = get_llm(model=model,embedding=False) - response = llm.predict(formatted_prompt) - predict_time = time.time() - start_time - logging.info(f"Response predicted in {predict_time:.2f} seconds") + response = cypher_res.get("result") + cypher_query = "" + context = [] + + for step in cypher_res.get("intermediate_steps", []): + if "query" in step: + cypher_string = step["query"] + cypher_query = cypher_string.replace("cypher\n", "").replace("\n", " ").strip() + elif "context" in step: + context = step["context"] + return { + "response": response, + "cypher_query": cypher_query, + "context": context + } + + except Exception as e: + logging.error(f"An error occurred while getting the graph response : {e}") - start_time = time.time() - ai_message = response - user_message = question - save_chat_history(history, user_message, ai_message) - chat_history_save = time.time() - start_time - logging.info(f"Chat History saved in {chat_history_save:.2f} seconds") +def process_graph_response(model, graph, question, messages, history): + try: + graph_chain, qa_llm, model_version = create_graph_chain(model, graph) - response_data = extract_and_remove_source(response) - message = response_data["message"] - sources = response_data["sources"] + graph_response = get_graph_response(graph_chain, question) - print(f"message : {message}") - print(f"sources : {sources}") - total_call_time = time.time() - qa_rag_start_time - logging.info(f"Total Response time is {total_call_time:.2f} seconds") - return { - "session_id": session_id, - "message": message, + ai_response_content = graph_response.get("response", "Something went wrong") + ai_response = AIMessage(content=ai_response_content) + + messages.append(ai_response) + summarize_and_log(history, messages, qa_llm) + + result = { + "session_id": "", + "message": ai_response_content, "info": { - "sources": sources, - "model":model_version, - "entities":vector_res["entities"] + "model": model_version, + "cypher_query": graph_response.get("cypher_query", ""), + "context": graph_response.get("context", ""), + "mode": "graph", + "response_time": 0 }, "user": "chatbot" - } - + } + + return result + except Exception as e: - logging.exception(f"Exception in QA component at {datetime.now()}: {str(e)}") - error_name = type(e).__name__ + logging.exception(f"Error processing graph response at {datetime.now()}: {str(e)}") return { - "session_id": session_id, + "session_id": "", "message": "Something went wrong", "info": { - "sources": [], - "error": f"{error_name} :- {str(e)}" + "model": model_version, + "cypher_query": "", + "context": "", + "mode": "graph", + "response_time": 0, + "error": f"{type(e).__name__}: {str(e)}" }, - "user": "chatbot"} + "user": "chatbot" + } + +def create_neo4j_chat_message_history(graph, session_id): + """ + Creates and returns a Neo4jChatMessageHistory instance. + + """ + try: + + history = Neo4jChatMessageHistory( + graph=graph, + session_id=session_id + ) + return history + + except Exception as e: + logging.error(f"Error creating Neo4jChatMessageHistory: {e}") + raise + +def get_chat_mode_settings(mode,settings_map=CHAT_MODE_CONFIG_MAP): + default_settings = settings_map["default"] + try: + chat_mode_settings = settings_map.get(mode, default_settings) + chat_mode_settings["mode"] = mode + + logging.info(f"Chat mode settings: {chat_mode_settings}") + except Exception as e: + logging.error(f"Unexpected error: {e}", exc_info=True) + raise + return chat_mode_settings + +def QA_RAG(graph, model, question, document_names, session_id, mode): + logging.info(f"Chat Mode: {mode}") + history = create_neo4j_chat_message_history(graph, session_id) + messages = history.messages + user_question = HumanMessage(content=question) + messages.append(user_question) + if mode == "graph": + result = process_graph_response(model, graph, question, messages, history) + else: + chat_mode_settings = get_chat_mode_settings(mode=mode) + result = process_chat_response(messages,history, question, model, graph, document_names,chat_mode_settings) + + result["session_id"] = session_id + + return result \ No newline at end of file diff --git a/backend/src/QA_integration_new.py b/backend/src/QA_integration_new.py deleted file mode 100644 index eeac78c1e..000000000 --- a/backend/src/QA_integration_new.py +++ /dev/null @@ -1,424 +0,0 @@ -from langchain_community.vectorstores.neo4j_vector import Neo4jVector -from langchain.graphs import Neo4jGraph -import os -from dotenv import load_dotenv -import logging -from langchain_community.chat_message_histories import Neo4jChatMessageHistory -from src.llm import get_llm -from src.shared.common_fn import load_embedding_model -import re -from typing import Any -from datetime import datetime -import time -from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder -from langchain_core.output_parsers import StrOutputParser -from langchain_core.runnables import RunnableBranch -from langchain.retrievers import ContextualCompressionRetriever -from langchain_community.document_transformers import EmbeddingsRedundantFilter -from langchain.retrievers.document_compressors import EmbeddingsFilter -from langchain.retrievers.document_compressors import DocumentCompressorPipeline -from langchain_text_splitters import TokenTextSplitter -from langchain_core.messages import HumanMessage,AIMessage -from src.shared.constants import * -from src.llm import get_llm -from langchain.chains import GraphCypherQAChain -import json - -## Chat models -from langchain_openai import ChatOpenAI, AzureChatOpenAI -from langchain_google_vertexai import ChatVertexAI -from langchain_groq import ChatGroq -from langchain_anthropic import ChatAnthropic -from langchain_fireworks import ChatFireworks -from langchain_aws import ChatBedrock -from langchain_community.chat_models import ChatOllama - -load_dotenv() - -EMBEDDING_MODEL = os.getenv('EMBEDDING_MODEL') -EMBEDDING_FUNCTION , _ = load_embedding_model(EMBEDDING_MODEL) - - -def get_neo4j_retriever(graph, retrieval_query,document_names,mode,index_name="vector",keyword_index="keyword", search_k=CHAT_SEARCH_KWARG_K, score_threshold=CHAT_SEARCH_KWARG_SCORE_THRESHOLD): - try: - if mode == "fulltext" or mode == "graph + vector + fulltext": - neo_db = Neo4jVector.from_existing_graph( - embedding=EMBEDDING_FUNCTION, - index_name=index_name, - retrieval_query=retrieval_query, - graph=graph, - search_type="hybrid", - node_label="Chunk", - embedding_node_property="embedding", - text_node_properties=["text"], - keyword_index_name=keyword_index - ) - # neo_db = Neo4jVector.from_existing_index( - # embedding=EMBEDDING_FUNCTION, - # index_name=index_name, - # retrieval_query=retrieval_query, - # graph=graph, - # search_type="hybrid", - # keyword_index_name=keyword_index - # ) - logging.info(f"Successfully retrieved Neo4jVector index '{index_name}' and keyword index '{keyword_index}'") - else: - neo_db = Neo4jVector.from_existing_index( - embedding=EMBEDDING_FUNCTION, - index_name=index_name, - retrieval_query=retrieval_query, - graph=graph - ) - logging.info(f"Successfully retrieved Neo4jVector index '{index_name}'") - document_names= list(map(str.strip, json.loads(document_names))) - if document_names: - retriever = neo_db.as_retriever(search_type="similarity_score_threshold",search_kwargs={'k': search_k, "score_threshold": score_threshold,'filter':{'fileName': {'$in': document_names}}}) - logging.info(f"Successfully created retriever for index '{index_name}' with search_k={search_k}, score_threshold={score_threshold} for documents {document_names}") - else: - retriever = neo_db.as_retriever(search_type="similarity_score_threshold",search_kwargs={'k': search_k, "score_threshold": score_threshold}) - logging.info(f"Successfully created retriever for index '{index_name}' with search_k={search_k}, score_threshold={score_threshold}") - return retriever - except Exception as e: - logging.error(f"Error retrieving Neo4jVector index '{index_name}' or creating retriever: {e}") - raise Exception("An error occurred while retrieving the Neo4jVector index '{index_name}' or creating the retriever. Please drop and create a new vector index: {e}") from e - -def create_document_retriever_chain(llm, retriever): - try: - logging.info("Starting to create document retriever chain") - - query_transform_prompt = ChatPromptTemplate.from_messages( - [ - ("system", QUESTION_TRANSFORM_TEMPLATE), - MessagesPlaceholder(variable_name="messages") - ] - ) - - output_parser = StrOutputParser() - - splitter = TokenTextSplitter(chunk_size=CHAT_DOC_SPLIT_SIZE, chunk_overlap=0) - embeddings_filter = EmbeddingsFilter( - embeddings=EMBEDDING_FUNCTION, - similarity_threshold=CHAT_EMBEDDING_FILTER_SCORE_THRESHOLD - ) - - pipeline_compressor = DocumentCompressorPipeline( - transformers=[splitter, embeddings_filter] - ) - - compression_retriever = ContextualCompressionRetriever( - base_compressor=pipeline_compressor, base_retriever=retriever - ) - - query_transforming_retriever_chain = RunnableBranch( - ( - lambda x: len(x.get("messages", [])) == 1, - (lambda x: x["messages"][-1].content) | compression_retriever, - ), - query_transform_prompt | llm | output_parser | compression_retriever, - ).with_config(run_name="chat_retriever_chain") - - logging.info("Successfully created document retriever chain") - return query_transforming_retriever_chain - - except Exception as e: - logging.error(f"Error creating document retriever chain: {e}", exc_info=True) - raise - - -def create_neo4j_chat_message_history(graph, session_id): - """ - Creates and returns a Neo4jChatMessageHistory instance. - - """ - try: - - history = Neo4jChatMessageHistory( - graph=graph, - session_id=session_id - ) - return history - - except Exception as e: - logging.error(f"Error creating Neo4jChatMessageHistory: {e}") - raise - -def format_documents(documents,model): - prompt_token_cutoff = 4 - for models,value in CHAT_TOKEN_CUT_OFF.items(): - if model in models: - prompt_token_cutoff = value - - sorted_documents = sorted(documents, key=lambda doc: doc.state["query_similarity_score"], reverse=True) - sorted_documents = sorted_documents[:prompt_token_cutoff] - - formatted_docs = [] - sources = set() - - for doc in sorted_documents: - source = doc.metadata['source'] - sources.add(source) - - formatted_doc = ( - "Document start\n" - f"This Document belongs to the source {source}\n" - f"Content: {doc.page_content}\n" - "Document end\n" - ) - formatted_docs.append(formatted_doc) - - return "\n\n".join(formatted_docs), sources - -def get_rag_chain(llm,system_template=CHAT_SYSTEM_TEMPLATE): - question_answering_prompt = ChatPromptTemplate.from_messages( - [ - ("system", system_template), - MessagesPlaceholder(variable_name="messages"), - ( - "human", - "User question: {input}" - ), - ] - ) - question_answering_chain = question_answering_prompt | llm - - return question_answering_chain - -def get_sources_and_chunks(sources_used, docs): - chunkdetails_list = [] - sources_used_set = set(sources_used) - - for doc in docs: - source = doc.metadata["source"] - chunkdetails = doc.metadata["chunkdetails"] - if source in sources_used_set: - chunkdetails = [{**chunkdetail, "score": round(chunkdetail["score"], 4)} for chunkdetail in chunkdetails] - chunkdetails_list.extend(chunkdetails) - - result = { - 'sources': sources_used, - 'chunkdetails': chunkdetails_list - } - return result - -def summarize_messages(llm,history,stored_messages): - if len(stored_messages) == 0: - return False - summarization_prompt = ChatPromptTemplate.from_messages( - [ - MessagesPlaceholder(variable_name="chat_history"), - ( - "human", - "Summarize the above chat messages into a concise message, focusing on key points and relevant details that could be useful for future conversations. Exclude all introductions and extraneous information." - ), - ] - ) - - summarization_chain = summarization_prompt | llm - - summary_message = summarization_chain.invoke({"chat_history": stored_messages}) - - history.clear() - history.add_user_message("Our current convertaion summary till now") - history.add_message(summary_message) - return True - - -def get_total_tokens(ai_response,llm): - - if isinstance(llm,(ChatOpenAI,AzureChatOpenAI,ChatFireworks,ChatGroq)): - total_tokens = ai_response.response_metadata['token_usage']['total_tokens'] - elif isinstance(llm,(ChatVertexAI)): - total_tokens = ai_response.response_metadata['usage_metadata']['prompt_token_count'] - elif isinstance(llm,(ChatBedrock)): - total_tokens = ai_response.response_metadata['usage']['total_tokens'] - elif isinstance(llm,(ChatAnthropic)): - input_tokens = int(ai_response.response_metadata['usage']['input_tokens']) - output_tokens = int(ai_response.response_metadata['usage']['output_tokens']) - total_tokens = input_tokens + output_tokens - elif isinstance(llm,(ChatOllama)): - total_tokens = ai_response.response_metadata["prompt_eval_count"] - else: - total_tokens = 0 - return total_tokens - - -def clear_chat_history(graph,session_id): - history = Neo4jChatMessageHistory( - graph=graph, - session_id=session_id - ) - history.clear() - return { - "session_id": session_id, - "message": "The chat History is cleared", - "user": "chatbot" - } - -def setup_chat(model, graph, document_names,retrieval_query,mode): - start_time = time.time() - if model in ["diffbot"]: - model = "openai-gpt-4o" - llm,model_name = get_llm(model) - logging.info(f"Model called in chat {model} and model version is {model_name}") - retriever = get_neo4j_retriever(graph=graph,retrieval_query=retrieval_query,document_names=document_names,mode=mode) - doc_retriever = create_document_retriever_chain(llm, retriever) - chat_setup_time = time.time() - start_time - logging.info(f"Chat setup completed in {chat_setup_time:.2f} seconds") - - return llm, doc_retriever, model_name - -def retrieve_documents(doc_retriever, messages): - start_time = time.time() - docs = doc_retriever.invoke({"messages": messages}) - doc_retrieval_time = time.time() - start_time - logging.info(f"Documents retrieved in {doc_retrieval_time:.2f} seconds") - return docs - -def process_documents(docs, question, messages, llm,model): - start_time = time.time() - formatted_docs, sources = format_documents(docs,model) - rag_chain = get_rag_chain(llm=llm) - ai_response = rag_chain.invoke({ - "messages": messages[:-1], - "context": formatted_docs, - "input": question - }) - result = get_sources_and_chunks(sources, docs) - content = ai_response.content - total_tokens = get_total_tokens(ai_response,llm) - - - predict_time = time.time() - start_time - logging.info(f"Final Response predicted in {predict_time:.2f} seconds") - - return content, result, total_tokens - -def summarize_and_log(history, messages, llm): - start_time = time.time() - summarize_messages(llm, history, messages) - history_summarized_time = time.time() - start_time - logging.info(f"Chat History summarized in {history_summarized_time:.2f} seconds") - - -def create_graph_chain(model, graph): - try: - logging.info(f"Graph QA Chain using LLM model: {model}") - - cypher_llm,model_name = get_llm(model) - qa_llm,model_name = get_llm(model) - graph_chain = GraphCypherQAChain.from_llm( - cypher_llm=cypher_llm, - qa_llm=qa_llm, - validate_cypher= True, - graph=graph, - # verbose=True, - return_intermediate_steps = True, - top_k=3 - ) - - logging.info("GraphCypherQAChain instance created successfully.") - return graph_chain,qa_llm,model_name - - except Exception as e: - logging.error(f"An error occurred while creating the GraphCypherQAChain instance. : {e}") - - -def get_graph_response(graph_chain, question): - try: - cypher_res = graph_chain.invoke({"query": question}) - - response = cypher_res.get("result") - cypher_query = "" - context = [] - - for step in cypher_res.get("intermediate_steps", []): - if "query" in step: - cypher_string = step["query"] - cypher_query = cypher_string.replace("cypher\n", "").replace("\n", " ").strip() - elif "context" in step: - context = step["context"] - return { - "response": response, - "cypher_query": cypher_query, - "context": context - } - - except Exception as e: - logging.error("An error occurred while getting the graph response : {e}") - -def QA_RAG(graph, model, question, document_names,session_id, mode): - try: - logging.info(f"Chat Mode : {mode}") - history = create_neo4j_chat_message_history(graph, session_id) - messages = history.messages - user_question = HumanMessage(content=question) - messages.append(user_question) - - if mode == "graph": - graph_chain, qa_llm,model_version = create_graph_chain(model,graph) - graph_response = get_graph_response(graph_chain,question) - ai_response = AIMessage(content=graph_response["response"]) if graph_response["response"] else AIMessage(content="Something went wrong") - messages.append(ai_response) - summarize_and_log(history, messages, qa_llm) - - result = { - "session_id": session_id, - "message": graph_response["response"], - "info": { - "model": model_version, - 'cypher_query':graph_response["cypher_query"], - "context" : graph_response["context"], - "mode" : mode, - "response_time": 0 - }, - "user": "chatbot" - } - return result - elif mode == "vector" or mode == "fulltext": - retrieval_query = VECTOR_SEARCH_QUERY - else: - retrieval_query = VECTOR_GRAPH_SEARCH_QUERY.format(no_of_entites=VECTOR_GRAPH_SEARCH_ENTITY_LIMIT) - - llm, doc_retriever, model_version = setup_chat(model, graph, document_names,retrieval_query,mode) - - docs = retrieve_documents(doc_retriever, messages) - - if docs: - content, result, total_tokens = process_documents(docs, question, messages, llm,model) - else: - content = "I couldn't find any relevant documents to answer your question." - result = {"sources": [], "chunkdetails": []} - total_tokens = 0 - - ai_response = AIMessage(content=content) - messages.append(ai_response) - summarize_and_log(history, messages, llm) - - return { - "session_id": session_id, - "message": content, - "info": { - "sources": result["sources"], - "model": model_version, - "chunkdetails": result["chunkdetails"], - "total_tokens": total_tokens, - "response_time": 0, - "mode": mode - }, - "user": "chatbot" - } - - except Exception as e: - logging.exception(f"Exception in QA component at {datetime.now()}: {str(e)}") - error_name = type(e).__name__ - return { - "session_id": session_id, - "message": "Something went wrong", - "info": { - "sources": [], - "chunkids": [], - "error": f"{error_name} :- {str(e)}", - "mode": mode - }, - "user": "chatbot" - } diff --git a/backend/src/QA_optimization.py b/backend/src/QA_optimization.py deleted file mode 100644 index 70c5ffdc8..000000000 --- a/backend/src/QA_optimization.py +++ /dev/null @@ -1,217 +0,0 @@ -import os -from langchain_community.vectorstores.neo4j_vector import Neo4jVector -from langchain.chains import GraphCypherQAChain -from langchain.graphs import Neo4jGraph -from langchain.chains import RetrievalQA -from langchain_openai import ChatOpenAI -from langchain_openai import OpenAIEmbeddings -import logging -from langchain_community.chat_message_histories import Neo4jChatMessageHistory -import asyncio -from datetime import datetime -from dotenv import load_dotenv -load_dotenv() - -# openai_api_key = os.environ.get('OPENAI_API_KEY') -# model_version='gpt-4-0125-preview' - -class ParallelComponent: - - def __init__(self, uri, userName, password, question, session_id): - self.uri = uri - self.userName = userName - self.password = password - self.question = question - self.session_id = session_id - self.model_version='gpt-4-0125-preview' - self.llm = ChatOpenAI(model= self.model_version, temperature=0) - - # async def execute(self): - # tasks = [] - - # tasks.append(asyncio.create_task(self._vector_embed_results())) - # tasks.append(asyncio.create_task(self._cypher_results())) - # tasks.append(asyncio.create_task(self._get_chat_history())) - - # return await asyncio.gather(*tasks) - async def execute(self): - tasks = [ - self._vector_embed_results(), - # self._cypher_results(), ## Disabled call for cypher_results - self._get_chat_history() - ] - return await asyncio.gather(*tasks) - - async def _vector_embed_results(self): - t=datetime.now() - print("Vector embeddings start time",t) - # retrieval_query=""" - # MATCH (node)-[:__PART_OF__]->(d:Document) - # WITH d, apoc.text.join(collect(node.text),"\n----\n") as text, avg(score) as score - # RETURN text, score, {source: COALESCE(CASE WHEN d.url CONTAINS "None" THEN d.fileName ELSE d.url END, d.fileName)} as metadata - # """ - retrieval_query=""" - WITH node, score, apoc.text.join([ (node)-[:__HAS_ENTITY__]->(e) | head(labels(e)) + ": "+ e.id],", ") as entities - MATCH (node)-[:__PART_OF__]->(d:__Document__) - WITH d, apoc.text.join(collect(node.text + "\n" + entities),"\n----\n") as text, avg(score) as score - RETURN text, score, {source: COALESCE(CASE WHEN d.url CONTAINS "None" THEN d.fileName ELSE d.url END, d.fileName)} as metadata - """ - vector_res={} - try: - neo_db=Neo4jVector.from_existing_index( - embedding=OpenAIEmbeddings(), - url=self.uri, - username=self.userName, - password=self.password, - database="neo4j", - index_name="vector", - retrieval_query=retrieval_query, - ) - # llm = ChatOpenAI(model= model_version, temperature=0) - - qa = RetrievalQA.from_chain_type( - llm=self.llm, chain_type="stuff", retriever=neo_db.as_retriever(search_kwargs={'k': 3,"score_threshold": 0.5}), return_source_documents=True - ) - - result = qa({"query": self.question}) - vector_res['result']=result.get("result") - list_source_docs=[] - for i in result["source_documents"]: - list_source_docs.append(i.metadata['source']) - vector_res['source']=list_source_docs - except Exception as e: - error_message = str(e) - logging.exception(f'Exception in vector embedding in QA component:{error_message}') - # raise Exception(error_message) - print("Vector embeddings duration time",datetime.now()-t) - return vector_res - - - async def _cypher_results(self): - try: - t=datetime.now() - print("Cypher QA start time",t) - cypher_res={} - graph = Neo4jGraph( - url=self.uri, - username=self.userName, - password=self.password - ) - - - graph.refresh_schema() - cypher_chain = GraphCypherQAChain.from_llm( - graph=graph, - cypher_llm=ChatOpenAI(temperature=0, model=self.model_version), - qa_llm=ChatOpenAI(temperature=0, model=self.model_version), - validate_cypher=True, # Validate relationship directions - verbose=True, - top_k=2 - ) - try: - cypher_res=cypher_chain.invoke({"query": question}) - except: - cypher_res={} - - except Exception as e: - error_message = str(e) - logging.exception(f'Exception in CypherQAChain in QA component:{error_message}') - # raise Exception(error_message) - print("Cypher QA duration",datetime.now()-t) - return cypher_res - - async def _get_chat_history(self): - try: - t=datetime.now() - print("Get chat history start time:",t) - history = Neo4jChatMessageHistory( - url=self.uri, - username=self.userName, - password=self.password, - session_id=self.session_id - ) - chat_history=history.messages - - if len(chat_history)==0: - return {"result":""} - condense_template = f"""Given the following earlier conversation , Summarise the chat history.Make sure to include all the relevant information. - Chat History: - {chat_history}""" - chat_summary=self.llm.predict(condense_template) - print("Get chat history duration time:",datetime.now()-t) - return {"result":chat_summary} - except Exception as e: - error_message = str(e) - logging.exception(f'Exception in retrieving chat history:{error_message}') - # raise Exception(error_message) - return {"result":''} - - async def final_prompt(self,chat_summary,cypher_res,vector_res): - t=datetime.now() - print('Final prompt start time:',t) - final_prompt = f"""You are a helpful question-answering agent. Your task is to analyze - and synthesize information from two sources: the top result from a similarity search - (unstructured information) and relevant data from a graph database (structured information). - If structured information fails to find an answer then use the answer from unstructured information - and vice versa. I only want a straightforward answer without mentioning from which source you got the answer. You are also receiving - a chat history of the earlier conversation. You should be able to understand the context from the chat history and answer the question. - Given the user's query: {self.question}, provide a meaningful and efficient answer based - on the insights derived from the following data: - chat_summary:{chat_summary} - Structured information: {cypher_res}. - Unstructured information: {vector_res}. - - """ - print(final_prompt) - response = self.llm.predict(final_prompt) - ai_message=response - user_message=question - print('Final prompt duration',datetime.now()-t) - return ai_message,user_message - - - async def _save_chat_history(self,ai_message,user_message): - try: - history = Neo4jChatMessageHistory( - url=self.uri, - username=self.userName, - password=self.password, - session_id=self.session_id - ) - history.add_user_message(user_message) - history.add_ai_message(ai_message) - logging.info(f'Successfully saved chat history') - except Exception as e: - error_message = str(e) - logging.exception(f'Exception in saving chat history:{error_message}') - raise Exception(error_message) - -# Usage example: - -uri=os.environ.get('NEO4J_URI') -userName=os.environ.get('NEO4J_USERNAME') -password=os.environ.get('NEO4J_PASSWORD') -question='Do you know my name?' -session_id=2 - -async def main(uri,userName,password,question,session_id): - t=datetime.now() - parallel_component = ParallelComponent(uri, userName, password, question, session_id) - f_results=await parallel_component.execute() - print(f_results) - # f_vector_result=f_results[0]['result'] - # f_cypher_result=f_results[1].get('result','') - # f_chat_summary=f_results[2]['result'] - f_vector_result=f_results[0]['result'] - f_cypher_result = "" # Passing Empty string for cypher_result - f_chat_summary=f_results[1]['result'] - print(f_vector_result) - print(f_cypher_result) - print(f_chat_summary) - ai_message,user_message=await parallel_component.final_prompt(f_chat_summary,f_cypher_result,f_vector_result) - # print(asyncio.gather(asyncio.create_taskparallel_component.final_prompt(f_chat_summary,f_cypher_result,f_vector_result))) - await parallel_component._save_chat_history(ai_message,user_message) - print("Total Time taken:",datetime.now()-t) - print("Response from AI:",ai_message) -# Run with an event loop -asyncio.run(main(uri,userName,password,question,session_id)) \ No newline at end of file diff --git a/backend/src/chunkid_entities.py b/backend/src/chunkid_entities.py index cdbd358d5..aa8d1d4ca 100644 --- a/backend/src/chunkid_entities.py +++ b/backend/src/chunkid_entities.py @@ -1,24 +1,6 @@ import logging -from neo4j import graph from src.graph_query import * - -CHUNK_QUERY = """ -match (chunk:Chunk) where chunk.id IN $chunksIds - -MATCH (chunk)-[:PART_OF]->(d:Document) -CALL {WITH chunk -MATCH (chunk)-[:HAS_ENTITY]->(e) -MATCH path=(e)(()-[rels:!HAS_ENTITY&!PART_OF]-()){0,2}(:!Chunk &! Document) -UNWIND rels as r -RETURN collect(distinct r) as rels -} -WITH d, collect(distinct chunk) as chunks, apoc.coll.toSet(apoc.coll.flatten(collect(rels))) as rels -RETURN d as doc, [chunk in chunks | chunk {.*, embedding:null}] as chunks, - [r in rels | {startNode:{element_id:elementId(startNode(r)), labels:labels(startNode(r)), properties:{id:startNode(r).id,description:startNode(r).description}}, - endNode:{element_id:elementId(endNode(r)), labels:labels(endNode(r)), properties:{id:endNode(r).id,description:endNode(r).description}}, - relationship: {type:type(r), element_id:elementId(r)}}] as entities -""" - +from src.shared.constants import * def process_records(records): """ @@ -37,10 +19,22 @@ def process_records(records): relationship = element['relationship'] if start_node['element_id'] not in seen_nodes: + if "labels" in start_node.keys(): + labels = set(start_node["labels"]) + labels.discard("__Entity__") + if not labels: + labels.add('*') + start_node["labels"] = list(labels) nodes.append(start_node) seen_nodes.add(start_node['element_id']) if end_node['element_id'] not in seen_nodes: + if "labels" in end_node.keys(): + labels = set(end_node["labels"]) + labels.discard("__Entity__") + if not labels: + labels.add('*') + end_node["labels"] = list(labels) nodes.append(end_node) seen_nodes.add(end_node['element_id']) @@ -86,8 +80,77 @@ def process_chunk_data(chunk_data): return chunk_properties except Exception as e: logging.error(f"chunkid_entities module: An error occurred while extracting the Chunk text from records: {e}") - -def get_entities_from_chunkids(uri, username, password, chunk_ids): + +def process_chunkids(driver, chunk_ids): + """ + Processes chunk IDs to retrieve chunk data. + """ + try: + logging.info(f"Starting graph query process for chunk ids: {chunk_ids}") + chunk_ids_list = chunk_ids.split(",") + + records, summary, keys = driver.execute_query(CHUNK_QUERY, chunksIds=chunk_ids_list) + result = process_records(records) + logging.info(f"Nodes and relationships are processed") + + result["chunk_data"] = process_chunk_data(records) + logging.info(f"Query process completed successfully for chunk ids: {chunk_ids}") + return result + except Exception as e: + logging.error(f"chunkid_entities module: Error processing chunk ids: {chunk_ids}. Error: {e}") + raise + +def remove_duplicate_nodes(nodes,property="element_id"): + unique_nodes = [] + seen_element_ids = set() + + for node in nodes: + element_id = node[property] + if element_id not in seen_element_ids: + if "labels" in node.keys(): + labels = set(node["labels"]) + labels.discard("__Entity__") + if not labels: + labels.add('*') + node["labels"] = list(labels) + unique_nodes.append(node) + seen_element_ids.add(element_id) + + return unique_nodes + +def process_entityids(driver, chunk_ids): + """ + Processes entity IDs to retrieve local community data. + """ + try: + logging.info(f"Starting graph query process for entity ids: {chunk_ids}") + entity_ids_list = chunk_ids.split(",") + query_body = LOCAL_COMMUNITY_SEARCH_QUERY.format( + topChunks=LOCAL_COMMUNITY_TOP_CHUNKS, + topCommunities=LOCAL_COMMUNITY_TOP_COMMUNITIES, + topOutsideRels=LOCAL_COMMUNITY_TOP_OUTSIDE_RELS + ) + query = LOCAL_COMMUNITY_DETAILS_QUERY_PREFIX + query_body + LOCAL_COMMUNITY_DETAILS_QUERY_SUFFIX + + records, summary, keys = driver.execute_query(query, entityIds=entity_ids_list) + + result = process_records(records) + if records: + result["nodes"].extend(records[0]["nodes"]) + result["nodes"] = remove_duplicate_nodes(result["nodes"]) + logging.info(f"Nodes and relationships are processed") + result["chunk_data"] = records[0]["chunks"] + result["community_data"] = records[0]["communities"] + else: + result["chunk_data"] = list() + result["community_data"] = list() + logging.info(f"Query process completed successfully for chunk ids: {chunk_ids}") + return result + except Exception as e: + logging.error(f"chunkid_entities module: Error processing entity ids: {chunk_ids}. Error: {e}") + raise + +def get_entities_from_chunkids(uri, username, password, database ,chunk_ids,is_entity=False): """ Retrieve and process nodes and relationships from a graph database given a list of chunk IDs. @@ -101,24 +164,32 @@ def get_entities_from_chunkids(uri, username, password, chunk_ids): dict: A dictionary with 'nodes' and 'relationships' keys containing processed data, or an error message. """ try: - logging.info(f"Starting graph query process for chunk ids") - if chunk_ids: - chunk_ids_list = chunk_ids.split(",") - driver = get_graphDB_driver(uri, username, password) - records, summary, keys = driver.execute_query(CHUNK_QUERY, chunksIds=chunk_ids_list) - result = process_records(records) - logging.info(f"Nodes and relationships are processed") - result["chunk_data"] = process_chunk_data(records) - logging.info(f"Query process completed successfully for chunk ids") + + driver = get_graphDB_driver(uri, username, password,database) + if not is_entity: + if chunk_ids: + logging.info(f"chunkid_entities module: Starting for chunk ids : {chunk_ids}") + result = process_chunkids(driver,chunk_ids) + else: + logging.info(f"chunkid_entities module: No chunk ids are passed") + result = { + "nodes": [], + "relationships": [], + "chunk_data":[] + } return result + if chunk_ids: + result = process_entityids(driver,chunk_ids) + logging.info(f"chunkid_entities module: Starting for entity ids : {chunk_ids}") else: - logging.info(f"chunkid_entities module: No chunk ids are passed") + logging.info(f"chunkid_entities module: No entity ids are passed") result = { "nodes": [], "relationships": [], - "chunk_data":[] + "chunk_data":[], + "community_data":[] } - return result + return result except Exception as e: logging.error(f"chunkid_entities module: An error occurred in get_entities_from_chunkids. Error: {str(e)}") diff --git a/backend/src/communities.py b/backend/src/communities.py new file mode 100644 index 000000000..7086a4786 --- /dev/null +++ b/backend/src/communities.py @@ -0,0 +1,408 @@ +import logging +from graphdatascience import GraphDataScience +from src.llm import get_llm +from langchain_core.prompts import ChatPromptTemplate +from langchain_core.output_parsers import StrOutputParser +from concurrent.futures import ThreadPoolExecutor, as_completed +import os +from src.shared.common_fn import load_embedding_model + + +COMMUNITY_PROJECTION_NAME = "communities" +NODE_PROJECTION = "!Chunk&!Document&!__Community__" +NODE_PROJECTION_ENTITY = "__Entity__" +MAX_WORKERS = 10 + + +CREATE_COMMUNITY_GRAPH_PROJECTION = """ +MATCH (source:{node_projection})-[]->(target:{node_projection}) +WITH source, target, count(*) as weight +WITH gds.graph.project( + '{project_name}', + source, + target, + {{ + relationshipProperties: {{ weight: weight }} + }}, + {{undirectedRelationshipTypes: ['*']}} + ) AS g +RETURN + g.graphName AS graph_name, g.nodeCount AS nodes, g.relationshipCount AS rels +""" + +CREATE_COMMUNITY_CONSTRAINT = "CREATE CONSTRAINT IF NOT EXISTS FOR (c:__Community__) REQUIRE c.id IS UNIQUE;" +CREATE_COMMUNITY_LEVELS = """ +MATCH (e:`__Entity__`) +WHERE e.communities is NOT NULL +UNWIND range(0, size(e.communities) - 1 , 1) AS index +CALL { + WITH e, index + WITH e, index + WHERE index = 0 + MERGE (c:`__Community__` {id: toString(index) + '-' + toString(e.communities[index])}) + ON CREATE SET c.level = index + MERGE (e)-[:IN_COMMUNITY]->(c) + RETURN count(*) AS count_0 +} +CALL { + WITH e, index + WITH e, index + WHERE index > 0 + MERGE (current:`__Community__` {id: toString(index) + '-' + toString(e.communities[index])}) + ON CREATE SET current.level = index + MERGE (previous:`__Community__` {id: toString(index - 1) + '-' + toString(e.communities[index - 1])}) + ON CREATE SET previous.level = index - 1 + MERGE (previous)-[:PARENT_COMMUNITY]->(current) + RETURN count(*) AS count_1 +} +RETURN count(*) +""" +CREATE_COMMUNITY_RANKS = """ +MATCH (c:__Community__)<-[:IN_COMMUNITY*]-(:!Chunk&!Document&!__Community__)<-[HAS_ENTITY]-(:Chunk)<-[]-(d:Document) +WITH c, count(distinct d) AS rank +SET c.community_rank = rank; +""" + +CREATE_PARENT_COMMUNITY_RANKS = """ +MATCH (c:__Community__)<-[:PARENT_COMMUNITY*]-(:__Community__)<-[:IN_COMMUNITY*]-(:!Chunk&!Document&!__Community__)<-[HAS_ENTITY]-(:Chunk)<-[]-(d:Document) +WITH c, count(distinct d) AS rank +SET c.community_rank = rank; +""" + +CREATE_COMMUNITY_WEIGHTS = """ +MATCH (n:`__Community__`)<-[:IN_COMMUNITY]-()<-[:HAS_ENTITY]-(c) +WITH n, count(distinct c) AS chunkCount +SET n.weight = chunkCount +""" +CREATE_PARENT_COMMUNITY_WEIGHTS = """ +MATCH (n:`__Community__`)<-[:PARENT_COMMUNITY*]-(:`__Community__`)<-[:IN_COMMUNITY]-()<-[:HAS_ENTITY]-(c) +WITH n, count(distinct c) AS chunkCount +SET n.weight = chunkCount +""" + +GET_COMMUNITY_INFO = """ +MATCH (c:`__Community__`)<-[:IN_COMMUNITY]-(e) +WHERE c.level = 0 +WITH c, collect(e) AS nodes +WHERE size(nodes) > 1 +CALL apoc.path.subgraphAll(nodes[0], { + whitelistNodes:nodes +}) +YIELD relationships +RETURN c.id AS communityId, + [n in nodes | {id: n.id, description: n.description, type: [el in labels(n) WHERE el <> '__Entity__'][0]}] AS nodes, + [r in relationships | {start: startNode(r).id, type: type(r), end: endNode(r).id}] AS rels +""" + +GET_PARENT_COMMUNITY_INFO = """ +MATCH (p:`__Community__`)<-[:PARENT_COMMUNITY*]-(c:`__Community__`) +WHERE p.summary is null and c.summary is not null +RETURN p.id as communityId, collect(c.summary) as texts +""" + + +STORE_COMMUNITY_SUMMARIES = """ +UNWIND $data AS row +MERGE (c:__Community__ {id:row.community}) +SET c.summary = row.summary +""" + +COMMUNITY_SYSTEM_TEMPLATE = "Given input triples, generate the information summary. No pre-amble." + +COMMUNITY_TEMPLATE = """Based on the provided nodes and relationships that belong to the same graph community, +generate a natural language summary of the provided information: +{community_info} + +Summary:""" + +PARENT_COMMUNITY_SYSTEM_TEMPLATE = "Given an input list of community summaries, generate a summary of the information" + +PARENT_COMMUNITY_TEMPLATE = """Based on the provided list of community summaries that belong to the same graph community, +generate a natural language summary of the information.Include all the necessary information as possible +{community_info} + +Summary:""" + + +GET_COMMUNITY_DETAILS = """ +MATCH (c:`__Community__`) +WHERE c.embedding IS NULL AND c.summary IS NOT NULL +RETURN c.id as communityId, c.summary as text +""" + +WRITE_COMMUNITY_EMBEDDINGS = """ +UNWIND $rows AS row +MATCH (c) WHERE c.id = row.communityId +CALL db.create.setNodeVectorProperty(c, "embedding", row.embedding) +""" + +DROP_COMMUNITIES = "MATCH (c:`__Community__`) DETACH DELETE c" +DROP_COMMUNITY_PROPERTY = "MATCH (e:`__Entity__`) REMOVE e.communities" + + +ENTITY_VECTOR_INDEX_NAME = "entity_vector" +ENTITY_VECTOR_EMBEDDING_DIMENSION = 384 + +CREATE_ENTITY_VECTOR_INDEX = """ +CREATE VECTOR INDEX {index_name} IF NOT EXISTS FOR (e:__Entity__) ON e.embedding +OPTIONS {{ + indexConfig: {{ + `vector.dimensions`: {embedding_dimension}, + `vector.similarity_function`: 'cosine' + }} +}} +""" + + +def get_gds_driver(uri, username, password, database): + try: + gds = GraphDataScience( + endpoint=uri, + auth=(username, password), + database=database + ) + logging.info("Successfully created GDS driver.") + return gds + except Exception as e: + logging.error(f"Failed to create GDS driver: {e}") + raise + +def create_community_graph_projection(gds, project_name=COMMUNITY_PROJECTION_NAME, node_projection=NODE_PROJECTION): + try: + existing_projects = gds.graph.list() + project_exists = existing_projects["graphName"].str.contains(project_name, regex=False).any() + + if project_exists: + logging.info(f"Projection '{project_name}' already exists. Dropping it.") + gds.graph.drop(project_name) + + logging.info(f"Creating new graph project '{project_name}'.") + projection_query = CREATE_COMMUNITY_GRAPH_PROJECTION.format(node_projection=node_projection,project_name=project_name) + graph_projection_result = gds.run_cypher(projection_query) + projection_result = graph_projection_result.to_dict(orient="records")[0] + logging.info(f"Graph projection '{projection_result['graph_name']}' created successfully with {projection_result['nodes']} nodes and {projection_result['rels']} relationships.") + graph_project = gds.graph.get(projection_result['graph_name']) + return graph_project + except Exception as e: + logging.error(f"Failed to create community graph project: {e}") + raise + +def write_communities(gds, graph_project, project_name=COMMUNITY_PROJECTION_NAME): + try: + logging.info(f"Writing communities to the graph project '{project_name}'.") + gds.leiden.write( + graph_project, + writeProperty=project_name, + includeIntermediateCommunities=True, + relationshipWeightProperty="weight" + ) + logging.info("Communities written successfully.") + return True + except Exception as e: + logging.error(f"Failed to write communities: {e}") + return False + + +def get_community_chain(model, is_parent=False,community_template=COMMUNITY_TEMPLATE,system_template=COMMUNITY_SYSTEM_TEMPLATE): + try: + if is_parent: + community_template=PARENT_COMMUNITY_TEMPLATE + system_template= PARENT_COMMUNITY_SYSTEM_TEMPLATE + llm, model_name = get_llm(model) + community_prompt = ChatPromptTemplate.from_messages( + [ + ( + "system", + system_template, + ), + ("human", community_template), + ] + ) + + community_chain = community_prompt | llm | StrOutputParser() + return community_chain + except Exception as e: + logging.error(f"Failed to create community chain: {e}") + raise + +def prepare_string(community_data): + try: + nodes_description = "Nodes are:\n" + for node in community_data['nodes']: + node_id = node['id'] + node_type = node['type'] + node_description = f", description: {node['description']}" if 'description' in node and node['description'] else "" + nodes_description += f"id: {node_id}, type: {node_type}{node_description}\n" + + relationships_description = "Relationships are:\n" + for rel in community_data['rels']: + start_node = rel['start'] + end_node = rel['end'] + relationship_type = rel['type'] + relationship_description = f", description: {rel['description']}" if 'description' in rel and rel['description'] else "" + relationships_description += f"({start_node})-[:{relationship_type}]->({end_node}){relationship_description}\n" + return nodes_description + "\n" + relationships_description + except Exception as e: + logging.error(f"Failed to prepare string from community data: {e}") + raise + +def process_community_info(community, chain, is_parent=False): + try: + if is_parent: + combined_text = " ".join(f"Summary {i+1}: {summary}" for i, summary in enumerate(community.get("texts", []))) + else: + combined_text = prepare_string(community) + summary = chain.invoke({'community_info': combined_text}) + return {"community": community['communityId'], "summary": summary} + except Exception as e: + logging.error(f"Failed to process community {community.get('communityId', 'unknown')}: {e}") + return None + +def create_community_summaries(gds, model): + try: + community_info_list = gds.run_cypher(GET_COMMUNITY_INFO) + community_chain = get_community_chain(model) + + summaries = [] + with ThreadPoolExecutor() as executor: + futures = [executor.submit(process_community_info, community, community_chain) for community in community_info_list.to_dict(orient="records")] + + for future in as_completed(futures): + result = future.result() + if result: + summaries.append(result) + else: + logging.error("community summaries could not be processed.") + + gds.run_cypher(STORE_COMMUNITY_SUMMARIES, params={"data": summaries}) + + parent_community_info = gds.run_cypher(GET_PARENT_COMMUNITY_INFO) + parent_community_chain = get_community_chain(model, is_parent=True) + + parent_summaries = [] + with ThreadPoolExecutor() as executor: + futures = [executor.submit(process_community_info, community, parent_community_chain, is_parent=True) for community in parent_community_info.to_dict(orient="records")] + + for future in as_completed(futures): + result = future.result() + if result: + parent_summaries.append(result) + else: + logging.error("parent community summaries could not be processed.") + + gds.run_cypher(STORE_COMMUNITY_SUMMARIES, params={"data": parent_summaries}) + + except Exception as e: + logging.error(f"Failed to create community summaries: {e}") + raise + +def create_community_embeddings(gds): + try: + embedding_model = os.getenv('EMBEDDING_MODEL') + embeddings, dimension = load_embedding_model(embedding_model) + logging.info(f"Embedding model '{embedding_model}' loaded successfully.") + + logging.info("Fetching community details.") + rows = gds.run_cypher(GET_COMMUNITY_DETAILS) + rows = rows[['communityId', 'text']].to_dict(orient='records') + logging.info(f"Fetched {len(rows)} communities.") + + batch_size = 100 + for i in range(0, len(rows), batch_size): + batch_rows = rows[i:i+batch_size] + for row in batch_rows: + try: + row['embedding'] = embeddings.embed_query(row['text']) + except Exception as e: + logging.error(f"Failed to embed text for community ID {row['communityId']}: {e}") + row['embedding'] = None + + try: + logging.info("Writing embeddings to the database.") + gds.run_cypher(WRITE_COMMUNITY_EMBEDDINGS, params={'rows': batch_rows}) + logging.info("Embeddings written successfully.") + except Exception as e: + logging.error(f"Failed to write embeddings to the database: {e}") + continue + return dimension + except Exception as e: + logging.error(f"An error occurred during the community embedding process: {e}") + +def create_entity_vector_index(gds, embedding_dimension=ENTITY_VECTOR_EMBEDDING_DIMENSION): + query = CREATE_ENTITY_VECTOR_INDEX.format( + index_name=ENTITY_VECTOR_INDEX_NAME, + embedding_dimension=embedding_dimension + ) + try: + logging.info(f"Running Cypher query to create entity vector index: {query}") + gds.run_cypher(query) + logging.info("Entity vector index created successfully.") + except Exception as e: + logging.error(f"Error occurred while creating entity vector index: {e}", exc_info=True) + +def create_community_properties(gds, model): + commands = [ + (CREATE_COMMUNITY_CONSTRAINT, "created community constraint to the graph."), + (CREATE_COMMUNITY_LEVELS, "Successfully created community levels."), + (CREATE_COMMUNITY_RANKS, "Successfully created community ranks."), + (CREATE_PARENT_COMMUNITY_RANKS, "Successfully created parent community ranks."), + (CREATE_COMMUNITY_WEIGHTS, "Successfully created community weights."), + (CREATE_PARENT_COMMUNITY_WEIGHTS, "Successfully created parent community weights."), + ] + try: + for command, message in commands: + gds.run_cypher(command) + logging.info(message) + + create_community_summaries(gds, model) + logging.info("Successfully created community summaries.") + + embedding_dimension = create_community_embeddings(gds) + logging.info("Successfully created community embeddings.") + + create_entity_vector_index(gds,embedding_dimension=embedding_dimension) + logging.info("Successfully created Entity Vector Index.") + + except Exception as e: + logging.error(f"Error during community properties creation: {e}") + raise + + +def clear_communities(gds): + try: + logging.info("Starting to clear communities.") + + logging.info("Dropping communities...") + gds.run_cypher(DROP_COMMUNITIES) + logging.info(f"Communities dropped successfully") + + logging.info("Dropping community property from entities...") + gds.run_cypher(DROP_COMMUNITY_PROPERTY) + logging.info(f"Community property dropped successfully") + + except Exception as e: + logging.error(f"An error occurred while clearing communities: {e}") + raise + + +def create_communities(uri, username, password, database,model): + try: + gds = get_gds_driver(uri, username, password, database) + clear_communities(gds) + + graph_project = create_community_graph_projection(gds) + write_communities_sucess = write_communities(gds, graph_project) + if write_communities_sucess: + logging.info("Starting Community properties creation process.") + create_community_properties(gds,model) + logging.info("Communities creation process completed successfully.") + else: + logging.warning("Failed to write communities. Constraint was not applied.") + except Exception as e: + logging.error(f"Failed to create communities: {e}") + + + + + + diff --git a/backend/src/graphDB_dataAccess.py b/backend/src/graphDB_dataAccess.py index 36a9a2925..279451bdf 100644 --- a/backend/src/graphDB_dataAccess.py +++ b/backend/src/graphDB_dataAccess.py @@ -140,6 +140,27 @@ def update_KNN_graph(self): ) else: logging.info("Vector index does not exist, So KNN graph not update") + + def check_gds_version(self): + try: + gds_procedure_count = """ + SHOW PROCEDURES + YIELD name + WHERE name STARTS WITH "gds." + RETURN COUNT(*) AS totalGdsProcedures + """ + result = self.graph.query(gds_procedure_count) + total_gds_procedures = result[0]['totalGdsProcedures'] if result else 0 + + if total_gds_procedures > 0: + logging.info("GDS is available in the database.") + return True + else: + logging.info("GDS is not available in the database.") + return False + except Exception as e: + logging.error(f"An error occurred while checking GDS version: {e}") + return False def connection_check_and_get_vector_dimensions(self): """ @@ -166,19 +187,20 @@ def connection_check_and_get_vector_dimensions(self): embedding_model = os.getenv('EMBEDDING_MODEL') embeddings, application_dimension = load_embedding_model(embedding_model) logging.info(f'embedding model:{embeddings} and dimesion:{application_dimension}') - # print(chunks_exists) + + gds_status = self.check_gds_version() if self.graph: if len(db_vector_dimension) > 0: - return {'db_vector_dimension': db_vector_dimension[0]['vector_dimensions'], 'application_dimension':application_dimension, 'message':"Connection Successful"} + return {'db_vector_dimension': db_vector_dimension[0]['vector_dimensions'], 'application_dimension':application_dimension, 'message':"Connection Successful","gds_status":gds_status} else: if len(db_vector_dimension) == 0 and len(result_chunks) == 0: logging.info("Chunks and vector index does not exists in database") - return {'db_vector_dimension': 0, 'application_dimension':application_dimension, 'message':"Connection Successful","chunks_exists":False} + return {'db_vector_dimension': 0, 'application_dimension':application_dimension, 'message':"Connection Successful","chunks_exists":False,"gds_status":gds_status} elif len(db_vector_dimension) == 0 and result_chunks[0]['hasEmbedding']==0 and result_chunks[0]['chunks'] > 0: - return {'db_vector_dimension': 0, 'application_dimension':application_dimension, 'message':"Connection Successful","chunks_exists":True} + return {'db_vector_dimension': 0, 'application_dimension':application_dimension, 'message':"Connection Successful","chunks_exists":True,"gds_status":gds_status} else: - return {'message':"Connection Successful"} + return {'message':"Connection Successful","gds_status":gds_status} def execute_query(self, query, param=None): return self.graph.query(query, param) diff --git a/backend/src/graph_query.py b/backend/src/graph_query.py index 5468fe2c3..fb7333b48 100644 --- a/backend/src/graph_query.py +++ b/backend/src/graph_query.py @@ -8,7 +8,7 @@ # watch("neo4j") -def get_graphDB_driver(uri, username, password): +def get_graphDB_driver(uri, username, password,database="neo4j"): """ Creates and returns a Neo4j database driver instance configured with the provided credentials. @@ -20,9 +20,9 @@ def get_graphDB_driver(uri, username, password): logging.info(f"Attempting to connect to the Neo4j database at {uri}") enable_user_agent = os.environ.get("ENABLE_USER_AGENT", "False").lower() in ("true", "1", "yes") if enable_user_agent: - driver = GraphDatabase.driver(uri, auth=(username, password), user_agent=os.environ.get('NEO4J_USER_AGENT')) + driver = GraphDatabase.driver(uri, auth=(username, password),database=database, user_agent=os.environ.get('NEO4J_USER_AGENT')) else: - driver = GraphDatabase.driver(uri, auth=(username, password)) + driver = GraphDatabase.driver(uri, auth=(username, password),database=database) logging.info("Connection successful") return driver except Exception as e: @@ -61,15 +61,20 @@ def process_node(node): with datetime objects formatted as ISO strings. """ try: + labels = set(node.labels) + labels.discard("__Entity__") + if not labels: + labels.add('*') + node_element = { "element_id": node.element_id, - "labels": list(node.labels), + "labels": list(labels), "properties": {} } # logging.info(f"Processing node with element ID: {node.element_id}") for key in node: - if key in ["embedding", "text"]: + if key in ["embedding", "text", "summary"]: continue value = node.get(key) if isinstance(value, time.DateTime): @@ -178,7 +183,7 @@ def get_completed_documents(driver): return documents -def get_graph_results(uri, username, password,document_names): +def get_graph_results(uri, username, password,database,document_names): """ Retrieves graph data by executing a specified Cypher query using credentials and parameters provided. Processes the results to extract nodes and relationships and packages them in a structured output. @@ -195,7 +200,7 @@ def get_graph_results(uri, username, password,document_names): """ try: logging.info(f"Starting graph query process") - driver = get_graphDB_driver(uri, username, password) + driver = get_graphDB_driver(uri, username, password,database) document_names= list(map(str.strip, json.loads(document_names))) query = GRAPH_QUERY.format(graph_chunk_limit=GRAPH_CHUNK_LIMIT) records, summary , keys = execute_query(driver, query.strip(), document_names) diff --git a/backend/src/llm.py b/backend/src/llm.py index 0ee61b650..505bb89fb 100644 --- a/backend/src/llm.py +++ b/backend/src/llm.py @@ -153,9 +153,11 @@ def get_graph_document_list( node_properties = False else: node_properties = ["description"] + relationship_properties = ["description"] llm_transformer = LLMGraphTransformer( llm=llm, node_properties=node_properties, + relationship_properties=relationship_properties, allowed_nodes=allowedNodes, allowed_relationships=allowedRelationship, ) diff --git a/backend/src/main.py b/backend/src/main.py index 7bf7c17bd..8bae03809 100644 --- a/backend/src/main.py +++ b/backend/src/main.py @@ -325,7 +325,6 @@ def processing_source(uri, userName, password, database, model, file_name, pages # selected_chunks = [] is_cancelled_status = False job_status = "Completed" - for i in range(0, len(chunkId_chunkDoc_list), update_graph_chunk_processed): select_chunks_upto = i+update_graph_chunk_processed logging.info(f'Selected Chunks upto: {select_chunks_upto}') diff --git a/backend/src/make_relationships.py b/backend/src/make_relationships.py index 4783c5abe..1ea2729e5 100644 --- a/backend/src/make_relationships.py +++ b/backend/src/make_relationships.py @@ -9,6 +9,9 @@ logging.basicConfig(format='%(asctime)s - %(message)s',level='INFO') +EMBEDDING_MODEL = os.getenv('EMBEDDING_MODEL') +EMBEDDING_FUNCTION , EMBEDDING_DIMENSION = load_embedding_model(EMBEDDING_MODEL) + def merge_relationship_between_chunk_and_entites(graph: Neo4jGraph, graph_documents_chunk_chunk_Id : list): batch_data = [] logging.info("Create HAS_ENTITY relationship between chunks and entities") @@ -39,9 +42,9 @@ def merge_relationship_between_chunk_and_entites(graph: Neo4jGraph, graph_docume def update_embedding_create_vector_index(graph, chunkId_chunkDoc_list, file_name): #create embedding isEmbedding = os.getenv('IS_EMBEDDING') - embedding_model = os.getenv('EMBEDDING_MODEL') + # embedding_model = os.getenv('EMBEDDING_MODEL') - embeddings, dimension = load_embedding_model(embedding_model) + embeddings, dimension = EMBEDDING_FUNCTION , EMBEDDING_DIMENSION logging.info(f'embedding model:{embeddings} and dimesion:{dimension}') data_for_query = [] logging.info(f"update embedding and vector index for chunks") diff --git a/backend/src/post_processing.py b/backend/src/post_processing.py index fa582e107..7d038c61b 100644 --- a/backend/src/post_processing.py +++ b/backend/src/post_processing.py @@ -8,7 +8,7 @@ DROP_INDEX_QUERY = "DROP INDEX entities IF EXISTS;" LABELS_QUERY = "CALL db.labels()" FULL_TEXT_QUERY = "CREATE FULLTEXT INDEX entities FOR (n{labels_str}) ON EACH [n.id, n.description];" -FILTER_LABELS = ["Chunk","Document"] +FILTER_LABELS = ["Chunk","Document","__Community__"] HYBRID_SEARCH_INDEX_DROP_QUERY = "DROP INDEX keyword IF EXISTS;" @@ -80,7 +80,7 @@ def create_entity_embedding(graph:Neo4jGraph): def fetch_entities_for_embedding(graph): query = """ MATCH (e) - WHERE NOT (e:Chunk OR e:Document) AND e.embedding IS NULL AND e.id IS NOT NULL + WHERE NOT (e:Chunk OR e:Document OR e:`__Community__`) AND e.embedding IS NULL AND e.id IS NOT NULL RETURN elementId(e) AS elementId, e.id + " " + coalesce(e.description, "") AS text """ result = graph.query(query) diff --git a/backend/src/shared/common_fn.py b/backend/src/shared/common_fn.py index b0dbe2f5f..6d24912c7 100644 --- a/backend/src/shared/common_fn.py +++ b/backend/src/shared/common_fn.py @@ -94,8 +94,8 @@ def load_embedding_model(embedding_model_name: str): return embeddings, dimension def save_graphDocuments_in_neo4j(graph:Neo4jGraph, graph_document_list:List[GraphDocument]): - # graph.add_graph_documents(graph_document_list, baseEntityLabel=True) - graph.add_graph_documents(graph_document_list) + graph.add_graph_documents(graph_document_list, baseEntityLabel=True,include_source=True) + # graph.add_graph_documents(graph_document_list) def handle_backticks_nodes_relationship_id_type(graph_document_list:List[GraphDocument]): for graph_document in graph_document_list: diff --git a/backend/src/shared/constants.py b/backend/src/shared/constants.py index c6d404a7f..7856dbec2 100644 --- a/backend/src/shared/constants.py +++ b/backend/src/shared/constants.py @@ -16,6 +16,7 @@ PROJECT_ID = 'llm-experiments-387609' GRAPH_CHUNK_LIMIT = 50 + #query GRAPH_QUERY = """ MATCH docs = (d:Document) @@ -38,15 +39,26 @@ CALL {{ WITH selectedChunks UNWIND selectedChunks as c - + OPTIONAL MATCH entities=(c:Chunk)-[:HAS_ENTITY]->(e) OPTIONAL MATCH entityRels=(e)--(e2:!Chunk) WHERE exists {{ (e2)<-[:HAS_ENTITY]-(other) WHERE other IN selectedChunks }} - RETURN collect(entities) as entities, collect(entityRels) as entityRels + RETURN entities , entityRels, collect(DISTINCT e) as entity }} +WITH docs,chunks,chunkRels, collect(entities) as entities, collect(entityRels) as entityRels, entity -WITH apoc.coll.flatten(docs + chunks + chunkRels + entities + entityRels, true) as paths +WITH * + +CALL {{ + with entity + unwind entity as n + OPTIONAL MATCH community=(n:__Entity__)-[:IN_COMMUNITY]->(p:__Community__) + OPTIONAL MATCH parentcommunity=(p)-[:PARENT_COMMUNITY*]->(p2:__Community__) + return collect(community) as communities , collect(parentcommunity) as parentCommunities +}} + +WITH apoc.coll.flatten(docs + chunks + chunkRels + entities + entityRels + communities + parentCommunities, true) as paths // distinct nodes and rels CALL {{ WITH paths UNWIND paths AS path UNWIND nodes(path) as node WITH distinct node @@ -56,9 +68,26 @@ """ +CHUNK_QUERY = """ +match (chunk:Chunk) where chunk.id IN $chunksIds + +MATCH (chunk)-[:PART_OF]->(d:Document) +CALL {WITH chunk +MATCH (chunk)-[:HAS_ENTITY]->(e) +MATCH path=(e)(()-[rels:!HAS_ENTITY&!PART_OF]-()){0,2}(:!Chunk &! Document &! `__Community__`) +UNWIND rels as r +RETURN collect(distinct r) as rels +} +WITH d, collect(distinct chunk) as chunks, apoc.coll.toSet(apoc.coll.flatten(collect(rels))) as rels +RETURN d as doc, [chunk in chunks | chunk {.*, embedding:null}] as chunks, + [r in rels | {startNode:{element_id:elementId(startNode(r)), labels:labels(startNode(r)), properties:{id:startNode(r).id,description:startNode(r).description}}, + endNode:{element_id:elementId(endNode(r)), labels:labels(endNode(r)), properties:{id:endNode(r).id,description:endNode(r).description}}, + relationship: {type:type(r), element_id:elementId(r)}}] as entities +""" + ## CHAT SETUP CHAT_MAX_TOKENS = 1000 -CHAT_SEARCH_KWARG_K = 3 +CHAT_SEARCH_KWARG_K = 10 CHAT_SEARCH_KWARG_SCORE_THRESHOLD = 0.5 CHAT_DOC_SPLIT_SIZE = 3000 CHAT_EMBEDDING_FILTER_SCORE_THRESHOLD = 0.10 @@ -69,6 +98,12 @@ } +CHAT_TOKEN_CUT_OFF = { + ("openai-gpt-3.5",'azure_ai_gpt_35',"gemini-1.0-pro","gemini-1.5-pro","groq-llama3",'groq_llama3_70b','anthropic_claude_3_5_sonnet','fireworks_llama_v3_70b','bedrock_claude_3_5_sonnet', ) : 4, + ("openai-gpt-4","diffbot" ,'azure_ai_gpt_4o',"openai-gpt-4o", "openai-gpt-4o-mini") : 28, + ("ollama_llama3") : 2 +} + ### CHAT TEMPLATES CHAT_SYSTEM_TEMPLATE = """ You are an AI-powered question-answering agent. Your task is to provide accurate and comprehensive responses to user queries based on the given context, chat history, and available resources. @@ -112,10 +147,8 @@ Note: This system does not generate answers based solely on internal knowledge. It answers from the information provided in the user's current and previous inputs, and from the context. """ - QUESTION_TRANSFORM_TEMPLATE = "Given the below conversation, generate a search query to look up in order to get information relevant to the conversation. Only respond with the query, nothing else." - ## CHAT QUERIES VECTOR_SEARCH_QUERY = """ WITH node AS chunk, score @@ -130,88 +163,6 @@ {source: COALESCE(CASE WHEN d.url CONTAINS "None" THEN d.fileName ELSE d.url END, d.fileName), chunkdetails: chunkdetails} as metadata """ -# VECTOR_GRAPH_SEARCH_QUERY=""" -# WITH node as chunk, score -# MATCH (chunk)-[:__PART_OF__]->(d:__Document__) -# CALL { WITH chunk -# MATCH (chunk)-[:__HAS_ENTITY__]->(e) -# MATCH path=(e)(()-[rels:!__HAS_ENTITY__&!__PART_OF__]-()){0,2}(:!__Chunk__&!__Document__) -# UNWIND rels as r -# RETURN collect(distinct r) as rels -# } -# WITH d, collect(DISTINCT {chunk: chunk, score: score}) AS chunks, avg(score) as avg_score, apoc.coll.toSet(apoc.coll.flatten(collect(rels))) as rels -# WITH d, avg_score, -# [c IN chunks | c.chunk.text] AS texts, -# [c IN chunks | {id: c.chunk.id, score: c.score}] AS chunkdetails, -# [r in rels | coalesce(apoc.coll.removeAll(labels(startNode(r)),['__Entity__'])[0],"") +":"+ startNode(r).id + " "+ type(r) + " " + coalesce(apoc.coll.removeAll(labels(endNode(r)),['__Entity__'])[0],"") +":" + endNode(r).id] as entities -# WITH d, avg_score,chunkdetails, -# apoc.text.join(texts,"\n----\n") + -# apoc.text.join(entities,"\n") -# as text -# RETURN text, avg_score AS score, {source: COALESCE( CASE WHEN d.url CONTAINS "None" THEN d.fileName ELSE d.url END, d.fileName), chunkdetails: chunkdetails} AS metadata -# """ - - -# VECTOR_GRAPH_SEARCH_QUERY = """ -# WITH node as chunk, score -# // find the document of the chunk -# MATCH (chunk)-[:__PART_OF__]->(d:__Document__) -# // fetch entities -# CALL { WITH chunk -# // entities connected to the chunk -# // todo only return entities that are actually in the chunk, remember we connect all extracted entities to all chunks -# MATCH (chunk)-[:__HAS_ENTITY__]->(e) - -# // depending on match to query embedding either 1 or 2 step expansion -# WITH CASE WHEN true // vector.similarity.cosine($embedding, e.embedding ) <= 0.95 -# THEN -# collect { MATCH path=(e)(()-[rels:!__HAS_ENTITY__&!__PART_OF__]-()){0,1}(:!Chunk&!__Document__) RETURN path } -# ELSE -# collect { MATCH path=(e)(()-[rels:!__HAS_ENTITY__&!__PART_OF__]-()){0,2}(:!Chunk&!__Document__) RETURN path } -# END as paths - -# RETURN collect{ unwind paths as p unwind relationships(p) as r return distinct r} as rels, -# collect{ unwind paths as p unwind nodes(p) as n return distinct n} as nodes -# } -# // aggregate chunk-details and de-duplicate nodes and relationships -# WITH d, collect(DISTINCT {chunk: chunk, score: score}) AS chunks, avg(score) as avg_score, apoc.coll.toSet(apoc.coll.flatten(collect(rels))) as rels, - -# // TODO sort by relevancy (embeddding comparision?) cut off after X (e.g. 25) nodes? -# apoc.coll.toSet(apoc.coll.flatten(collect( -# [r in rels |[startNode(r),endNode(r)]]),true)) as nodes - -# // generate metadata and text components for chunks, nodes and relationships -# WITH d, avg_score, -# [c IN chunks | c.chunk.text] AS texts, -# [c IN chunks | {id: c.chunk.id, score: c.score}] AS chunkdetails, -# apoc.coll.sort([n in nodes | - -# coalesce(apoc.coll.removeAll(labels(n),['__Entity__'])[0],"") +":"+ -# n.id + (case when n.description is not null then " ("+ n.description+")" else "" end)]) as nodeTexts, -# apoc.coll.sort([r in rels -# // optional filter if we limit the node-set -# // WHERE startNode(r) in nodes AND endNode(r) in nodes -# | -# coalesce(apoc.coll.removeAll(labels(startNode(r)),['__Entity__'])[0],"") +":"+ -# startNode(r).id + -# " " + type(r) + " " + -# coalesce(apoc.coll.removeAll(labels(endNode(r)),['__Entity__'])[0],"") +":" + -# endNode(r).id -# ]) as relTexts - -# // combine texts into response-text -# WITH d, avg_score,chunkdetails, -# "Text Content:\n" + -# apoc.text.join(texts,"\n----\n") + -# "\n----\nEntities:\n"+ -# apoc.text.join(nodeTexts,"\n") + -# "\n----\nRelationships:\n"+ -# apoc.text.join(relTexts,"\n") - -# as text -# RETURN text, avg_score as score, {length:size(text), source: COALESCE( CASE WHEN d.url CONTAINS "None" THEN d.fileName ELSE d.url END, d.fileName), chunkdetails: chunkdetails} AS metadata -# """ - VECTOR_GRAPH_SEARCH_ENTITY_LIMIT = 25 VECTOR_GRAPH_SEARCH_QUERY = """ @@ -276,6 +227,118 @@ RETURN text, avg_score as score, {{length:size(text), source: COALESCE( CASE WHEN d.url CONTAINS "None" THEN d.fileName ELSE d.url END, d.fileName), chunkdetails: chunkdetails}} AS metadata """ + +### Local community search +LOCAL_COMMUNITY_TOP_K = 10 +LOCAL_COMMUNITY_TOP_CHUNKS = 3 +LOCAL_COMMUNITY_TOP_COMMUNITIES = 3 +LOCAL_COMMUNITY_TOP_OUTSIDE_RELS = 10 + +LOCAL_COMMUNITY_SEARCH_QUERY = """ +WITH collect(node) as nodes, avg(score) as score, collect({{id: elementId(node), score:score}}) as metadata +WITH score, nodes,metadata, +collect {{ + UNWIND nodes as n + MATCH (n)<-[:HAS_ENTITY]->(c:Chunk) + WITH c, count(distinct n) as freq + RETURN c + ORDER BY freq DESC + LIMIT {topChunks} +}} AS chunks, +collect {{ + UNWIND nodes as n + MATCH (n)-[:IN_COMMUNITY]->(c:__Community__) + WITH c, c.community_rank as rank, c.weight AS weight + RETURN c + ORDER BY rank, weight DESC + LIMIT {topCommunities} +}} AS communities, +collect {{ + unwind nodes as n + unwind nodes as m + match (n)-[r]->(m) + RETURN distinct r + // todo should we have a limit here? +}} as rels, +collect {{ + unwind nodes as n + match path = (n)-[r]-(m:__Entity__) + where not m in nodes + with m, collect(distinct r) as rels, count(*) as freq + ORDER BY freq DESC LIMIT {topOutsideRels} + WITH collect(m) as outsideNodes, apoc.coll.flatten(collect(rels)) as rels + RETURN {{ nodes: outsideNodes, rels: rels }} +}} as outside +""" + +LOCAL_COMMUNITY_SEARCH_QUERY_SUFFIX = """ +RETURN {chunks: [c in chunks | c.text], + communities: [c in communities | c.summary], + entities: [n in nodes | apoc.coll.removeAll(labels(n),["__Entity__"])[0] + ":"+ n.id + " " + coalesce(n.description, "")], + relationships: [r in rels | startNode(r).id+" "+type(r)+" "+endNode(r).id], + outside: { + nodes: [n in outside[0].nodes | apoc.coll.removeAll(labels(n),["__Entity__"])[0] + ":"+n.id + " " + coalesce(n.description, "")], + relationships: [r in outside[0].rels | apoc.coll.removeAll(labels(startNode(r)),["__Entity__"])[0] + ":"+startNode(r).id+" "+type(r)+" "+apoc.coll.removeAll(labels(startNode(r)),["__Entity__"])[0] + ":"+endNode(r).id]} + } AS text, score, {entities:metadata} as metadata +""" + +LOCAL_COMMUNITY_DETAILS_QUERY_PREFIX = """ +UNWIND $entityIds as id +MATCH (node) WHERE elementId(node) = id +WITH node, 1.0 as score +""" +LOCAL_COMMUNITY_DETAILS_QUERY_SUFFIX = """ +WITH * +UNWIND chunks as c +MATCH (c)-[:PART_OF]->(d:Document) +RETURN [c {.*, embedding:null, fileName:d.fileName, fileSource:d.fileSource}] as chunks, +[community in communities | community {.*, embedding:null}] as communities, +[node in nodes+outside[0].nodes | {element_id:elementId(node), labels:labels(node), properties:{id:node.id,description:node.description}}] as nodes, +[r in rels+outside[0].rels | {startNode:{element_id:elementId(startNode(r)), labels:labels(startNode(r)), properties:{id:startNode(r).id,description:startNode(r).description}}, + endNode:{element_id:elementId(endNode(r)), labels:labels(endNode(r)), properties:{id:endNode(r).id,description:endNode(r).description}}, + relationship: {type:type(r), element_id:elementId(r)}}] as entities +""" + +CHAT_MODE_CONFIG_MAP= { + "vector": { + "retrieval_query": VECTOR_SEARCH_QUERY, + "index_name": "vector", + "keyword_index": None, + "document_filter": True + }, + "fulltext": { + "retrieval_query": VECTOR_SEARCH_QUERY, + "index_name": "vector", + "keyword_index": "keyword", + "document_filter": False + }, + "entity search+vector": { + "retrieval_query": LOCAL_COMMUNITY_SEARCH_QUERY.format(topChunks=LOCAL_COMMUNITY_TOP_CHUNKS, + topCommunities=LOCAL_COMMUNITY_TOP_COMMUNITIES, + topOutsideRels=LOCAL_COMMUNITY_TOP_OUTSIDE_RELS)+LOCAL_COMMUNITY_SEARCH_QUERY_SUFFIX, + "index_name": "entity_vector", + "keyword_index": None, + "document_filter": False + }, + "graph+vector": { + "retrieval_query": VECTOR_GRAPH_SEARCH_QUERY.format(no_of_entites=VECTOR_GRAPH_SEARCH_ENTITY_LIMIT), + "index_name": "vector", + "keyword_index": None, + "document_filter": True + }, + "graph+vector+fulltext": { + "retrieval_query": VECTOR_GRAPH_SEARCH_QUERY.format(no_of_entites=VECTOR_GRAPH_SEARCH_ENTITY_LIMIT), + "index_name": "vector", + "keyword_index": "keyword", + "document_filter": False + }, + "default": { + "retrieval_query": VECTOR_SEARCH_QUERY, + "index_name": "vector", + "keyword_index": None, + "document_filter": True + } + } YOUTUBE_CHUNK_SIZE_SECONDS = 60 QUERY_TO_GET_CHUNKS = """ diff --git a/experiments/graphrag.ipynb b/experiments/graphrag.ipynb new file mode 100644 index 000000000..a3f99796a --- /dev/null +++ b/experiments/graphrag.ipynb @@ -0,0 +1,3519 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# !pip install --quiet --upgrade langchain-community langchain-experimental langchain-openai neo4j graphdatascience tiktoken retry" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/workspaces/llm-graph-builder/chatbotenv/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", + " from .autonotebook import tqdm as notebook_tqdm\n" + ] + } + ], + "source": [ + "import getpass\n", + "import os\n", + "from langchain_community.graphs import Neo4jGraph\n", + "from graphdatascience import GraphDataScience\n", + "import pandas as pd\n", + "import numpy as np\n", + "from langchain_core.prompts import ChatPromptTemplate\n", + "from langchain_core.output_parsers import StrOutputParser\n", + "from src.llm import get_llm\n", + "\n", + "import os\n", + "import getpass\n", + "from neo4j import GraphDatabase, Result\n", + "import pandas as pd\n", + "import seaborn as sns\n", + "import matplotlib.pyplot as plt\n", + "import tiktoken\n", + "import numpy as np\n", + "from langchain_openai import OpenAIEmbeddings, ChatOpenAI\n", + "from langchain_community.vectorstores import Neo4jVector\n", + "from langchain_community.graphs import Neo4jGraph\n", + "from langchain_core.prompts import ChatPromptTemplate\n", + "from langchain_core.output_parsers import StrOutputParser\n", + "# from llama_index.core.schema import TextNode\n", + "# from llama_index.core.vector_stores.utils import node_to_metadata_dict\n", + "# from llama_index.vector_stores.neo4jvector import Neo4jVectorStore\n", + "# from llama_index.core import VectorStoreIndex\n", + "from tqdm import tqdm\n", + "from src.shared.common_fn import load_embedding_model\n", + "\n", + "\n", + "from typing import Dict, Any\n", + "from concurrent.futures import ThreadPoolExecutor, as_completed\n", + "from tqdm import tqdm\n", + "from src.llm import get_llm" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "os.environ[\"NEO4J_URI\"] = \"\"\n", + "os.environ[\"NEO4J_USERNAME\"] = \"neo4j\"\n", + "os.environ[\"NEO4J_PASSWORD\"] = \"\"\n", + "os.environ[\"OPENAI_API_KEY\"] = \"\"" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Received notification from DBMS server: {severity: WARNING} {code: Neo.ClientNotification.Statement.FeatureDeprecationWarning} {category: DEPRECATION} {title: This feature is deprecated and will be removed in future versions.} {description: The query used a deprecated field from a procedure. ('advertisedListenAddress' returned by 'gds.debug.arrow' is deprecated.)} {position: line: 1, column: 1, offset: 0} for query: 'CALL gds.debug.arrow()'\n", + "Received notification from DBMS server: {severity: WARNING} {code: Neo.ClientNotification.Statement.FeatureDeprecationWarning} {category: DEPRECATION} {title: This feature is deprecated and will be removed in future versions.} {description: The query used a deprecated field from a procedure. ('serverLocation' returned by 'gds.debug.arrow' is deprecated.)} {position: line: 1, column: 1, offset: 0} for query: 'CALL gds.debug.arrow()'\n" + ] + } + ], + "source": [ + "gds = GraphDataScience(\n", + " os.environ[\"NEO4J_URI\"],\n", + " auth=(os.environ[\"NEO4J_USERNAME\"], os.environ[\"NEO4J_PASSWORD\"])\n", + ")\n", + "\n", + "graph = Neo4jGraph() \n", + "\n", + "driver = GraphDatabase.driver(os.environ[\"NEO4J_URI\"], auth=(os.environ[\"NEO4J_USERNAME\"], os.environ[\"NEO4J_PASSWORD\"]))" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'type': 'node', 'total_count': 185, 'non_null_descriptions': 146},\n", + " {'type': 'relationship', 'total_count': 14614, 'non_null_descriptions': 41}]" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "graph.query(\"\"\"\n", + "MATCH (n:`__Entity__`)\n", + "RETURN \"node\" AS type,\n", + " count(*) AS total_count,\n", + " count(n.description) AS non_null_descriptions\n", + "UNION ALL\n", + "MATCH (n)-[r:!MENTIONS]->()\n", + "RETURN \"relationship\" AS type,\n", + " count(*) AS total_count,\n", + " count(r.description) AS non_null_descriptions\n", + "\"\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Received notification from DBMS server: {severity: WARNING} {code: Neo.ClientNotification.Statement.FeatureDeprecationWarning} {category: DEPRECATION} {title: This feature is deprecated and will be removed in future versions.} {description: The query used a deprecated field from a procedure. ('schema' returned by 'gds.graph.list' is deprecated.)} {position: line: 1, column: 1, offset: 0} for query: 'CALL gds.graph.list()'\n" + ] + } + ], + "source": [ + "available_graphs = gds.graph.list()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "available_graphs.drop([0,1],inplace=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
    \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
    degreeDistributiongraphNamedatabasedatabaseLocationmemoryUsagesizeInBytesnodeCountrelationshipCountconfigurationdensitycreationTimemodificationTimeschemaschemaWithOrientation
    \n", + "
    " + ], + "text/plain": [ + "Empty DataFrame\n", + "Columns: [degreeDistribution, graphName, database, databaseLocation, memoryUsage, sizeInBytes, nodeCount, relationshipCount, configuration, density, creationTime, modificationTime, schema, schemaWithOrientation]\n", + "Index: []" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "available_graphs" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "available_graphs[\"graphName\"].str.contains('communities', regex=False).any()" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Received notification from DBMS server: {severity: WARNING} {code: Neo.ClientNotification.Statement.FeatureDeprecationWarning} {category: DEPRECATION} {title: This feature is deprecated and will be removed in future versions.} {description: The query used a deprecated field from a procedure. ('schema' returned by 'gds.graph.drop' is deprecated.)} {position: line: 1, column: 1, offset: 0} for query: 'CALL gds.graph.drop($graph_name, $fail_if_missing, $db_name)'\n" + ] + }, + { + "data": { + "text/plain": [ + "graphName communities\n", + "database neo4j\n", + "databaseLocation local\n", + "memoryUsage \n", + "sizeInBytes -1\n", + "nodeCount 185\n", + "relationshipCount 366\n", + "configuration {'relationshipProjection': {'_ALL_': {'aggrega...\n", + "density 0.010752\n", + "creationTime 2024-08-19T12:41:43.997435629+00:00\n", + "modificationTime 2024-08-19T12:41:44.127124307+00:00\n", + "schema {'graphProperties': {}, 'nodes': {'__Entity__'...\n", + "schemaWithOrientation {'graphProperties': {}, 'nodes': {'__Entity__'...\n", + "Name: 0, dtype: object" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gds.graph.drop(\"communities\")" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "G, result = gds.graph.project(\n", + " \"communities\", # Graph name\n", + " \"__Entity__\", # Node projection\n", + " {\n", + " \"_ALL_\": {\n", + " \"type\": \"*\",\n", + " \"orientation\": \"UNDIRECTED\",\n", + " \"properties\": {\"weight\": {\"property\": \"*\", \"aggregation\": \"COUNT\"}},\n", + " }\n", + " },\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "nodeProjection {'__Entity__': {'label': '__Entity__', 'proper...\n", + "relationshipProjection {'_ALL_': {'aggregation': 'DEFAULT', 'orientat...\n", + "graphName communities\n", + "nodeCount 185\n", + "relationshipCount 366\n", + "projectMillis 15\n", + "Name: 0, dtype: object" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "result" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Received notification from DBMS server: {severity: WARNING} {code: Neo.ClientNotification.Statement.FeatureDeprecationWarning} {category: DEPRECATION} {title: This feature is deprecated and will be removed in future versions.} {description: The query used a deprecated field from a procedure. ('schema' returned by 'gds.graph.list' is deprecated.)} {position: line: 1, column: 106, offset: 105} for query: 'CALL gds.graph.list($graph_name) YIELD graphName, nodeCount, relationshipCount, database, configuration, schema, memoryUsage'\n" + ] + }, + { + "data": { + "text/plain": [ + "Graph({'graphName': 'communities', 'nodeCount': 185, 'relationshipCount': 366, 'database': 'neo4j', 'configuration': {'relationshipProjection': {'_ALL_': {'aggregation': 'DEFAULT', 'orientation': 'UNDIRECTED', 'indexInverse': False, 'properties': {'weight': {'aggregation': 'COUNT', 'property': '*', 'defaultValue': None}}, 'type': '*'}}, 'readConcurrency': 4, 'relationshipProperties': {}, 'nodeProperties': {}, 'jobId': 'ced0b057-a717-48d8-8b90-842f6f2aa001', 'nodeProjection': {'__Entity__': {'label': '__Entity__', 'properties': {}}}, 'logProgress': True, 'creationTime': neo4j.time.DateTime(2024, 8, 19, 13, 10, 3, 641071700, tzinfo=), 'validateRelationships': False, 'sudo': False}, 'schema': {'graphProperties': {}, 'nodes': {'__Entity__': {}}, 'relationships': {'_ALL_': {'weight': 'Float (DefaultValue(NaN), PERSISTENT, Aggregation.COUNT)'}}}, 'memoryUsage': '2316 KiB'})" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "G" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'COMMUNITY_PROJECT_NAME'" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\"community_project_name\".upper()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Component count: 14\n", + "Component distribution: {'min': 1, 'p5': 1, 'max': 155, 'p999': 155, 'p99': 155, 'p1': 1, 'p10': 1, 'p90': 3, 'p50': 1, 'p25': 1, 'p75': 2, 'p95': 155, 'mean': 12.285714285714286}\n" + ] + } + ], + "source": [ + "wcc = gds.wcc.stats(G)\n", + "print(f\"Component count: {wcc['componentCount']}\")\n", + "print(f\"Component distribution: {wcc['componentDistribution']}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "writeMillis 5\n", + "nodePropertiesWritten 172\n", + "ranLevels 2\n", + "didConverge True\n", + "nodeCount 172\n", + "communityCount 22\n", + "communityDistribution {'min': 1, 'p5': 1, 'max': 64, 'p999': 64, 'p9...\n", + "modularity 0.678705\n", + "modularities [0.6566821889989846, 0.6787052274080039]\n", + "postProcessingMillis 3\n", + "preProcessingMillis 0\n", + "computeMillis 33\n", + "configuration {'writeProperty': 'communities', 'theta': 0.01...\n", + "Name: 0, dtype: object" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gds.leiden.write(\n", + " G,\n", + " writeProperty=\"communities\",\n", + " includeIntermediateCommunities=True,\n", + " relationshipWeightProperty=\"weight\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "graph.query(\"CREATE CONSTRAINT IF NOT EXISTS FOR (c:__Community__) REQUIRE c.id IS UNIQUE;\")" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'count(*)': 344}]" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "graph.query(\"\"\"\n", + "MATCH (e:`__Entity__`)\n", + "UNWIND range(0, size(e.communities) - 1 , 1) AS index\n", + "CALL {\n", + " WITH e, index\n", + " WITH e, index\n", + " WHERE index = 0\n", + " MERGE (c:`__Community__` {id: toString(index) + '-' + toString(e.communities[index])})\n", + " ON CREATE SET c.level = index\n", + " MERGE (e)-[:IN_COMMUNITY]->(c)\n", + " RETURN count(*) AS count_0\n", + "}\n", + "CALL {\n", + " WITH e, index\n", + " WITH e, index\n", + " WHERE index > 0\n", + " MERGE (current:`__Community__` {id: toString(index) + '-' + toString(e.communities[index])})\n", + " ON CREATE SET current.level = index\n", + " MERGE (previous:`__Community__` {id: toString(index - 1) + '-' + toString(e.communities[index - 1])})\n", + " ON CREATE SET previous.level = index - 1\n", + " MERGE (previous)-[:IN_COMMUNITY]->(current)\n", + " RETURN count(*) AS count_1\n", + "}\n", + "RETURN count(*)\n", + "\"\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "graph.query(\"\"\"\n", + "MATCH (c:__Community__)<-[:IN_COMMUNITY*]-(:__Entity__)<-[:MENTIONS]-(d:Document)\n", + "WITH c, count(distinct d) AS rank\n", + "SET c.community_rank = rank;\n", + "\"\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
    \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
    LevelNumber of communities25th Percentile50th Percentile75th Percentile90th Percentile99th PercentileMax
    00281.02.03.7513.949.6661
    11221.02.08.5017.854.5564
    \n", + "
    " + ], + "text/plain": [ + " Level Number of communities 25th Percentile 50th Percentile \\\n", + "0 0 28 1.0 2.0 \n", + "1 1 22 1.0 2.0 \n", + "\n", + " 75th Percentile 90th Percentile 99th Percentile Max \n", + "0 3.75 13.9 49.66 61 \n", + "1 8.50 17.8 54.55 64 " + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\n", + "community_size = graph.query(\n", + " \"\"\"\n", + "MATCH (c:__Community__)<-[:IN_COMMUNITY*]-(e:__Entity__)\n", + "WITH c, count(distinct e) AS entities\n", + "RETURN split(c.id, '-')[0] AS level, entities\n", + "\"\"\"\n", + ")\n", + "community_size_df = pd.DataFrame.from_records(community_size)\n", + "percentiles_data = []\n", + "for level in community_size_df[\"level\"].unique():\n", + " subset = community_size_df[community_size_df[\"level\"] == level][\"entities\"]\n", + " num_communities = len(subset)\n", + " percentiles = np.percentile(subset, [25, 50, 75, 90, 99])\n", + " percentiles_data.append(\n", + " [\n", + " level,\n", + " num_communities,\n", + " percentiles[0],\n", + " percentiles[1],\n", + " percentiles[2],\n", + " percentiles[3],\n", + " percentiles[4],\n", + " max(subset)\n", + " ]\n", + " )\n", + "\n", + "# Create a DataFrame with the percentiles\n", + "percentiles_df = pd.DataFrame(\n", + " percentiles_data,\n", + " columns=[\n", + " \"Level\",\n", + " \"Number of communities\",\n", + " \"25th Percentile\",\n", + " \"50th Percentile\",\n", + " \"75th Percentile\",\n", + " \"90th Percentile\",\n", + " \"99th Percentile\",\n", + " \"Max\"\n", + " ],\n", + ")\n", + "percentiles_df\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### community summaries" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "community_info = graph.query(\"\"\"\n", + "MATCH (c:`__Community__`)<-[:IN_COMMUNITY*]-(e:__Entity__)\n", + "WHERE c.level IN [0,1,4]\n", + "WITH c, collect(e ) AS nodes\n", + "WHERE size(nodes) > 1\n", + "CALL apoc.path.subgraphAll(nodes[0], {\n", + "\twhitelistNodes:nodes\n", + "})\n", + "YIELD relationships\n", + "RETURN c.id AS communityId,\n", + " [n in nodes | {id: n.id, description: n.description, type: [el in labels(n) WHERE el <> '__Entity__'][0]}] AS nodes,\n", + " [r in relationships | {start: startNode(r).id, type: type(r), end: endNode(r).id, description: r.description}] AS rels\n", + "\"\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'communityId': '0-36',\n", + " 'nodes': [{'id': 'India',\n", + " 'description': 'Officially the Republic of India, located in South Asia.',\n", + " 'type': 'Country'},\n", + " {'id': 'Supreme Court Of India',\n", + " 'description': 'Head of the independent judiciary.',\n", + " 'type': 'Judiciary'},\n", + " {'id': 'Indian National Congress',\n", + " 'description': 'Dominated Indian politics until 1977.',\n", + " 'type': 'Political party'},\n", + " {'id': 'Sindhu',\n", + " 'description': 'Name of the Indus River, from which the name India is derived.',\n", + " 'type': 'River'},\n", + " {'id': 'Food And Agriculture Organization Of The United Nations',\n", + " 'description': \"Estimates India's forest cover.\",\n", + " 'type': 'Organization'},\n", + " {'id': '2013 Forest Survey Of India',\n", + " 'description': \"States India's forest cover increased to 69.8 million hectares by 2012.\",\n", + " 'type': 'Report'},\n", + " {'id': 'Yajnavalkya Smriti',\n", + " 'description': 'Prohibited the cutting of trees.',\n", + " 'type': 'Literature'},\n", + " {'id': 'Kautalyas Arthashastra',\n", + " 'description': 'Discusses the need for forest administration.',\n", + " 'type': 'Literature'},\n", + " {'id': 'Crown Land (Encroachment) Ordinance',\n", + " 'description': \"Promulgated in 1840 targeting forests in Britain's Asian colonies.\",\n", + " 'type': 'Legislation'},\n", + " {'id': 'Indian Forest Act Of 1865',\n", + " 'description': \"Established the government's claims over forests.\",\n", + " 'type': 'Legislation'},\n", + " {'id': 'Forest Act Of 1878',\n", + " 'description': 'Gave the British government control over all wastelands, including forests.',\n", + " 'type': 'Legislation'},\n", + " {'id': 'Sir Dietrich Brandis',\n", + " 'description': 'Inspector General of Forests in India from 1864 to 1883.',\n", + " 'type': 'Person'},\n", + " {'id': 'Indian Ocean',\n", + " 'description': 'Ocean bounded by India on the north.',\n", + " 'type': 'Ocean'},\n", + " {'id': 'Sri Lanka',\n", + " 'description': 'Country in the vicinity of India in the Indian Ocean.',\n", + " 'type': 'Country'},\n", + " {'id': 'Maldives',\n", + " 'description': 'Country in the vicinity of India in the Indian Ocean.',\n", + " 'type': 'Country'},\n", + " {'id': 'Myanmar',\n", + " 'description': 'Country sharing land border with India to the east.',\n", + " 'type': 'Country'},\n", + " {'id': 'Himalayan Mountain Range',\n", + " 'description': 'Defines the northern frontiers of India.',\n", + " 'type': 'Mountain range'},\n", + " {'id': 'China',\n", + " 'description': 'Country sharing land border with India to the north.',\n", + " 'type': 'Country'},\n", + " {'id': 'Bhutan',\n", + " 'description': 'Country sharing land border with India to the north.',\n", + " 'type': 'Country'},\n", + " {'id': 'Nepal',\n", + " 'description': 'Country sharing land border with India to the north.',\n", + " 'type': 'Country'},\n", + " {'id': 'Pakistan',\n", + " 'description': 'Country sharing land border with India to the west.',\n", + " 'type': 'Country'},\n", + " {'id': 'Bangladesh',\n", + " 'description': 'Country sharing land border with India to the east.',\n", + " 'type': 'Country'},\n", + " {'id': 'Ganges',\n", + " 'description': 'The longest river originating in India.',\n", + " 'type': 'River'},\n", + " {'id': 'Western Ghats',\n", + " 'description': 'One of the three biodiversity hotspots in India.',\n", + " 'type': 'Biodiversity hotspot'},\n", + " {'id': 'Eastern Himalayas',\n", + " 'description': 'One of the three biodiversity hotspots in India.',\n", + " 'type': 'Biodiversity hotspot'},\n", + " {'id': 'Indo-Burma Hotspot',\n", + " 'description': 'One of the three biodiversity hotspots in India.',\n", + " 'type': 'Biodiversity hotspot'},\n", + " {'id': 'Forests',\n", + " 'description': 'Covers about 24.6% of the total land area.',\n", + " 'type': 'Ecosystem'},\n", + " {'id': 'Indomalayan Realm',\n", + " 'description': 'Geographical realm that includes India.',\n", + " 'type': 'Realm'},\n", + " {'id': 'World', 'description': None, 'type': None},\n", + " {'id': 'Public_Sector', 'description': None, 'type': None},\n", + " {'id': 'Gdp', 'description': None, 'type': None},\n", + " {'id': 'Economic_Liberalisation', 'description': None, 'type': None},\n", + " {'id': 'Gdp_Growth', 'description': None, 'type': None},\n", + " {'id': 'Consumer_Market', 'description': None, 'type': None},\n", + " {'id': 'Wto', 'description': None, 'type': None},\n", + " {'id': 'Ease_Of_Business_Index', 'description': None, 'type': None},\n", + " {'id': 'Global_Competitiveness_Index', 'description': None, 'type': None},\n", + " {'id': 'Billionaires', 'description': None, 'type': None},\n", + " {'id': 'Welfare_State', 'description': None, 'type': None},\n", + " {'id': 'Socialist_State', 'description': None, 'type': None},\n", + " {'id': 'Social_Welfare_Spending', 'description': None, 'type': None},\n", + " {'id': 'Labour_Force', 'description': None, 'type': None},\n", + " {'id': 'Fdi', 'description': None, 'type': None},\n", + " {'id': 'Free_Trade_Agreements', 'description': None, 'type': None},\n", + " {'id': 'Service_Sector', 'description': None, 'type': None},\n", + " {'id': 'Stock_Exchanges', 'description': None, 'type': None},\n", + " {'id': 'Manufacturing', 'description': None, 'type': None},\n", + " {'id': 'Population', 'description': None, 'type': None},\n", + " {'id': 'Unemployment', 'description': None, 'type': None},\n", + " {'id': 'Savings_Rate', 'description': None, 'type': None},\n", + " {'id': 'Arabian Sea',\n", + " 'description': 'Sea bounded by India on the northwest.',\n", + " 'type': 'Sea'},\n", + " {'id': 'Bay Of Bengal',\n", + " 'description': 'Bay bounded by India on the southeast.',\n", + " 'type': 'Bay'},\n", + " {'id': 'Africa',\n", + " 'description': 'Continent from which modern humans arrived on the Indian subcontinent.',\n", + " 'type': 'Continent'},\n", + " {'id': 'Indus Valley Civilisation',\n", + " 'description': 'Civilisation that evolved from settled life in the western margins of the Indus river basin.',\n", + " 'type': 'Civilization'},\n", + " {'id': 'Sanskrit',\n", + " 'description': 'Indo-European language that diffused into India from the northwest.',\n", + " 'type': 'Language'},\n", + " {'id': 'Rigveda',\n", + " 'description': 'Ancient hymns recording the dawning of Hinduism in India.',\n", + " 'type': 'Text'},\n", + " {'id': 'Hinduism',\n", + " 'description': 'Major religion in India, with roots in the Rigveda.',\n", + " 'type': 'Religion'},\n", + " {'id': 'Buddhism',\n", + " 'description': 'Religion that arose in India, proclaiming social orders unlinked to heredity.',\n", + " 'type': 'Religion'},\n", + " {'id': 'Jainism',\n", + " 'description': 'Religion that arose in India, proclaiming social orders unlinked to heredity.',\n", + " 'type': 'Religion'},\n", + " {'id': 'Mughal Empire',\n", + " 'description': 'Empire that began in 1526, known for its architecture and relative peace.',\n", + " 'type': 'Empire'},\n", + " {'id': 'Indian Republic',\n", + " 'description': 'India has been a federal republic since 1950.',\n", + " 'type': 'Government'}],\n", + " 'rels': [{'start': 'India',\n", + " 'description': None,\n", + " 'type': 'IS_PART_OF',\n", + " 'end': 'Indomalayan Realm'},\n", + " {'start': 'India',\n", + " 'description': 'About 1,900 public sector companies with complete control and ownership of railways, highways, and majority control in various industries.',\n", + " 'type': 'HAS',\n", + " 'end': 'Public_Sector'},\n", + " {'start': 'India',\n", + " 'description': \"One of the world's highest number of billionaires.\",\n", + " 'type': 'HAS',\n", + " 'end': 'Billionaires'},\n", + " {'start': 'India',\n", + " 'description': \"World's second-largest labour force with 586 million workers.\",\n", + " 'type': 'HAS',\n", + " 'end': 'Labour_Force'},\n", + " {'start': 'India',\n", + " 'description': 'Has free trade agreements with several nations and blocs.',\n", + " 'type': 'HAS',\n", + " 'end': 'Free_Trade_Agreements'},\n", + " {'start': 'India',\n", + " 'description': \"Bombay Stock Exchange and National Stock Exchange are among the world's largest stock exchanges.\",\n", + " 'type': 'HAS',\n", + " 'end': 'Stock_Exchanges'},\n", + " {'start': 'India',\n", + " 'description': \"Nearly 65% of India's population is rural.\",\n", + " 'type': 'HAS',\n", + " 'end': 'Population'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'RELATES_TO',\n", + " 'end': 'Rigveda'},\n", + " {'start': 'India',\n", + " 'description': 'Member of the World Trade Organization since 1 January 1995.',\n", + " 'type': 'MEMBER_OF',\n", + " 'end': 'Wto'},\n", + " {'start': 'India',\n", + " 'description': 'High unemployment and rising income inequality.',\n", + " 'type': 'FACES',\n", + " 'end': 'Unemployment'},\n", + " {'start': 'India',\n", + " 'description': 'Adopted broad economic liberalisation in 1991.',\n", + " 'type': 'ADOPTED',\n", + " 'end': 'Economic_Liberalisation'},\n", + " {'start': 'India',\n", + " 'description': 'Often considered a welfare state.',\n", + " 'type': 'CONSIDERED_AS',\n", + " 'end': 'Welfare_State'},\n", + " {'start': 'India', 'description': None, 'type': 'NEAR', 'end': 'Sri Lanka'},\n", + " {'start': 'India', 'description': None, 'type': 'NEAR', 'end': 'Maldives'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'BORDERS',\n", + " 'end': 'Indian Ocean'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'BORDERS',\n", + " 'end': 'Myanmar'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'BORDERS',\n", + " 'end': 'Himalayan Mountain Range'},\n", + " {'start': 'India', 'description': None, 'type': 'BORDERS', 'end': 'China'},\n", + " {'start': 'India', 'description': None, 'type': 'BORDERS', 'end': 'Bhutan'},\n", + " {'start': 'India', 'description': None, 'type': 'BORDERS', 'end': 'Nepal'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'BORDERS',\n", + " 'end': 'Pakistan'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'BORDERS',\n", + " 'end': 'Bangladesh'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'BORDERS',\n", + " 'end': 'Arabian Sea'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'BORDERS',\n", + " 'end': 'Bay Of Bengal'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'SEPARATED_BY',\n", + " 'end': 'Sri Lanka'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'DERIVED_FROM',\n", + " 'end': 'Sindhu'},\n", + " {'start': 'India',\n", + " 'description': \"Estimates India's forest cover.\",\n", + " 'type': 'ESTIMATES',\n", + " 'end': 'Food And Agriculture Organization Of The United Nations'},\n", + " {'start': 'India',\n", + " 'description': 'Makes up more than 50% of GDP.',\n", + " 'type': 'MAKES_UP',\n", + " 'end': 'Service_Sector'},\n", + " {'start': 'India',\n", + " 'description': 'Fifth-largest economy by nominal GDP and third-largest by purchasing power parity (PPP).',\n", + " 'type': 'RANKS_AS',\n", + " 'end': 'World'},\n", + " {'start': 'India',\n", + " 'description': 'Fourth-largest consumer market in the world.',\n", + " 'type': 'RANKS_AS',\n", + " 'end': 'Consumer_Market'},\n", + " {'start': 'India',\n", + " 'description': \"World's sixth-largest manufacturer, representing 2.6% of global manufacturing output.\",\n", + " 'type': 'RANKS_AS',\n", + " 'end': 'Manufacturing'},\n", + " {'start': 'India',\n", + " 'description': 'Officially declared a socialist state as per the constitution.',\n", + " 'type': 'DECLARED_AS',\n", + " 'end': 'Socialist_State'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'ORIGIN_OF',\n", + " 'end': 'Hinduism'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'ORIGIN_OF',\n", + " 'end': 'Buddhism'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'ORIGIN_OF',\n", + " 'end': 'Jainism'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'GOVERNED_AS',\n", + " 'end': 'Indian Republic'},\n", + " {'start': 'India',\n", + " 'description': '136th by GDP (nominal) and 125th by GDP (PPP) on a per capita income basis.',\n", + " 'type': 'RANKS',\n", + " 'end': 'Gdp'},\n", + " {'start': 'India',\n", + " 'description': '63rd on the Ease of Doing Business index.',\n", + " 'type': 'RANKS',\n", + " 'end': 'Ease_Of_Business_Index'},\n", + " {'start': 'India',\n", + " 'description': '40th on the Global Competitiveness Index.',\n", + " 'type': 'RANKS',\n", + " 'end': 'Global_Competitiveness_Index'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'SHARES_BORDERS_WITH',\n", + " 'end': 'Myanmar'},\n", + " {'start': 'India',\n", + " 'description': 'Overall social welfare spending stood at 8.6% of GDP in 2021-22.',\n", + " 'type': 'SPENDING',\n", + " 'end': 'Social_Welfare_Spending'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'HISTORICAL_EVENT',\n", + " 'end': 'Mughal Empire'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'ORIGINATES_IN',\n", + " 'end': 'Ganges'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'HAS_BIODIVERSITY_HOTSPOT',\n", + " 'end': 'Western Ghats'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'HAS_BIODIVERSITY_HOTSPOT',\n", + " 'end': 'Eastern Himalayas'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'HAS_BIODIVERSITY_HOTSPOT',\n", + " 'end': 'Indo-Burma Hotspot'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'HAS_ECOSYSTEM',\n", + " 'end': 'Forests'},\n", + " {'start': 'India',\n", + " 'description': '6% to 7% since the start of the 21st century.',\n", + " 'type': 'AVERAGE_ANNUAL_GROWTH',\n", + " 'end': 'Gdp_Growth'},\n", + " {'start': 'India',\n", + " 'description': 'Foreign direct investment in 2021-22 was $82 billion.',\n", + " 'type': 'FOREIGN_DIRECT_INVESTMENT',\n", + " 'end': 'Fdi'},\n", + " {'start': 'India',\n", + " 'description': 'Gross domestic savings rate stood at 29.3% of GDP in 2022.',\n", + " 'type': 'GROSS_DOMESTIC_SAVINGS_RATE',\n", + " 'end': 'Savings_Rate'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'HUMAN_ORIGIN',\n", + " 'end': 'Africa'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'HISTORICAL_DEVELOPMENT',\n", + " 'end': 'Indus Valley Civilisation'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'LANGUAGE_DIFFUSION',\n", + " 'end': 'Sanskrit'},\n", + " {'start': 'Kautalyas Arthashastra',\n", + " 'description': 'Discusses the need for forest administration.',\n", + " 'type': 'DISCUSSES',\n", + " 'end': 'India'},\n", + " {'start': 'Indian Forest Act Of 1865',\n", + " 'description': \"Establishes government's claims over forests.\",\n", + " 'type': 'ESTABLISHES',\n", + " 'end': 'India'},\n", + " {'start': 'Crown Land (Encroachment) Ordinance',\n", + " 'description': \"Targets forests in Britain's Asian colonies.\",\n", + " 'type': 'TARGETS',\n", + " 'end': 'India'},\n", + " {'start': 'Yajnavalkya Smriti',\n", + " 'description': 'Prohibits the cutting of trees.',\n", + " 'type': 'PROHIBITS',\n", + " 'end': 'India'},\n", + " {'start': '2013 Forest Survey Of India',\n", + " 'description': 'Reports on forest cover increase.',\n", + " 'type': 'REPORTS_ON',\n", + " 'end': 'India'},\n", + " {'start': 'Supreme Court Of India',\n", + " 'description': None,\n", + " 'type': 'PART_OF_JUDICIARY',\n", + " 'end': 'India'},\n", + " {'start': 'Indian National Congress',\n", + " 'description': None,\n", + " 'type': 'HISTORICALLY_DOMINANT_PARTY',\n", + " 'end': 'India'},\n", + " {'start': 'Forest Act Of 1878',\n", + " 'description': 'Gives control over all wastelands, including forests.',\n", + " 'type': 'GIVES_CONTROL',\n", + " 'end': 'India'},\n", + " {'start': 'Sir Dietrich Brandis',\n", + " 'description': 'Inspector General of Forests in India from 1864 to 1883.',\n", + " 'type': 'INSPECTOR_GENERAL_OF',\n", + " 'end': 'India'}]},\n", + " {'communityId': '0-34',\n", + " 'nodes': [{'id': 'Constitution Of India',\n", + " 'description': 'The supreme law of India, laying down the framework for government institutions and fundamental rights.',\n", + " 'type': 'Document'},\n", + " {'id': 'Parliament',\n", + " 'description': 'Cannot override the Constitution of India.',\n", + " 'type': 'Institution'},\n", + " {'id': 'Government Of India Act 1935',\n", + " 'description': 'Replaced by the Constitution of India.',\n", + " 'type': 'Document'},\n", + " {'id': 'Constituent Assembly',\n", + " 'description': 'Tasked with drafting the Constitution of India.',\n", + " 'type': 'Government body'},\n", + " {'id': 'M. N. Roy',\n", + " 'description': 'Proposed the framework for the Constitution of India.',\n", + " 'type': 'Person'},\n", + " {'id': 'Republic Day',\n", + " 'description': 'Celebrated on 26 January in India to honor the Constitution.',\n", + " 'type': 'Event'},\n", + " {'id': 'Old Parliament House',\n", + " 'description': 'Preserves the original 1950 Constitution in a nitrogen-filled case.',\n", + " 'type': 'Location'},\n", + " {'id': 'British Government',\n", + " 'description': 'Responsible for the external security of India during its dominion status.',\n", + " 'type': 'Institution'},\n", + " {'id': 'Indian Independence Act 1947',\n", + " 'description': 'Repealed by the Constitution of India.',\n", + " 'type': 'Document'},\n", + " {'id': 'Articles Of The Constitution',\n", + " 'description': 'Articles 5, 6, 7, 8, 9, 60, 324, 366, 367, 379, 380, 388, 391, 392, 393, and 394 came into force on 26 November 1949.',\n", + " 'type': 'Document'}],\n", + " 'rels': [{'start': 'Constitution Of India',\n", + " 'description': 'The Constitution is based on the proposal suggested by M. N. Roy.',\n", + " 'type': 'BASED_ON',\n", + " 'end': 'M. N. Roy'},\n", + " {'start': 'Constitution Of India',\n", + " 'description': 'The original 1950 Constitution is preserved in a nitrogen-filled case.',\n", + " 'type': 'PRESERVED_IN',\n", + " 'end': 'Old Parliament House'},\n", + " {'start': 'Constitution Of India',\n", + " 'description': 'Celebrated on 26 January.',\n", + " 'type': 'CELEBRATED_ON',\n", + " 'end': 'Republic Day'},\n", + " {'start': 'Constitution Of India',\n", + " 'description': 'Parliament cannot override the Constitution.',\n", + " 'type': 'CANNOT_OVERRIDE',\n", + " 'end': 'Parliament'},\n", + " {'start': 'Constitution Of India',\n", + " 'description': 'Certain articles came into force on 26 November 1949.',\n", + " 'type': 'CAME_INTO_FORCE',\n", + " 'end': 'Articles Of The Constitution'},\n", + " {'start': 'Government Of India Act 1935',\n", + " 'description': 'Replaced by the Constitution of India.',\n", + " 'type': 'REPLACED_BY',\n", + " 'end': 'Constitution Of India'},\n", + " {'start': 'British Government',\n", + " 'description': 'Responsible for the external security of India during its dominion status.',\n", + " 'type': 'RESPONSIBLE_FOR',\n", + " 'end': 'Constitution Of India'},\n", + " {'start': 'Indian Independence Act 1947',\n", + " 'description': 'Repealed by the Constitution of India.',\n", + " 'type': 'REPEALED_BY',\n", + " 'end': 'Constitution Of India'},\n", + " {'start': 'Constituent Assembly',\n", + " 'description': None,\n", + " 'type': 'DRAFTED_BY',\n", + " 'end': 'Constitution Of India'}]},\n", + " {'communityId': '0-25',\n", + " 'nodes': [{'id': 'President Of India',\n", + " 'description': 'The Supreme Commander of the Indian Armed Forces.',\n", + " 'type': 'Person'},\n", + " {'id': 'Nda',\n", + " 'description': 'A coalition of the BJP and its allies governing India since 2014.',\n", + " 'type': 'Political alliance'},\n", + " {'id': 'Government Of India',\n", + " 'description': 'Established a system of national parks and protected areas.',\n", + " 'type': 'Government'},\n", + " {'id': 'Narendra Modi',\n", + " 'description': 'Current Prime Minister of India since 26 May 2014.',\n", + " 'type': 'Person'},\n", + " {'id': 'New Delhi',\n", + " 'description': 'The seat of the Government of India.',\n", + " 'type': 'Location'},\n", + " {'id': 'Supreme Court',\n", + " 'description': 'The highest judicial forum and final court of appeal under the Constitution of India.',\n", + " 'type': 'Judiciary'},\n", + " {'id': 'Indian Councils Act 1909',\n", + " 'description': 'Introduced elections to the Imperial Legislative Council.',\n", + " 'type': 'Legislation'},\n", + " {'id': 'Government Of India Act 1919',\n", + " 'description': 'Expanded the Imperial Legislative Council.',\n", + " 'type': 'Legislation'},\n", + " {'id': 'National Parks',\n", + " 'description': 'Established in 1935 and expanded to nearly 1022 by 2023.',\n", + " 'type': 'Protected area'},\n", + " {'id': 'Wildlife Protection Act Of 1972',\n", + " 'description': 'Enacted for the protection of wildlife.',\n", + " 'type': 'Legislation'},\n", + " {'id': 'Project Tiger',\n", + " 'description': 'Special project for the protection of critical species.',\n", + " 'type': 'Conservation project'},\n", + " {'id': 'Project Elephant',\n", + " 'description': 'Special project for the protection of critical species.',\n", + " 'type': 'Conservation project'},\n", + " {'id': 'Project Dolphin',\n", + " 'description': 'Special project for the protection of critical species.',\n", + " 'type': 'Conservation project'}],\n", + " 'rels': [{'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'INITIATED',\n", + " 'end': 'Project Tiger'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'INITIATED',\n", + " 'end': 'Project Elephant'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'INITIATED',\n", + " 'end': 'Project Dolphin'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'GOVERNED_BY',\n", + " 'end': 'Nda'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'ENACTED',\n", + " 'end': 'Wildlife Protection Act Of 1972'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'ESTABLISHED',\n", + " 'end': 'National Parks'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'LEAD_BY',\n", + " 'end': 'Narendra Modi'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'RESPONSIBLE_TO',\n", + " 'end': 'Supreme Court'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'SEATED_IN',\n", + " 'end': 'New Delhi'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'HEAD_OF_STATE',\n", + " 'end': 'President Of India'},\n", + " {'start': 'Indian Councils Act 1909',\n", + " 'description': None,\n", + " 'type': 'INFLUENCED',\n", + " 'end': 'Government Of India'},\n", + " {'start': 'Government Of India Act 1919',\n", + " 'description': None,\n", + " 'type': 'INFLUENCED',\n", + " 'end': 'Government Of India'}]},\n", + " {'communityId': '0-112',\n", + " 'nodes': [{'id': 'Prime Minister Of India',\n", + " 'description': 'Holds executive authority and responsibility for national security.',\n", + " 'type': 'Person'},\n", + " {'id': 'Indian Armed Forces',\n", + " 'description': 'The military forces of the Republic of India.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Indian Army',\n", + " 'description': 'One of the three professional uniformed services of the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Indian Navy',\n", + " 'description': 'One of the three professional uniformed services of the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Indian Air Force',\n", + " 'description': 'One of the three professional uniformed services of the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Central Armed Police Forces',\n", + " 'description': 'Supports the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Indian Coast Guard',\n", + " 'description': 'Supports the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Special Frontier Force',\n", + " 'description': 'Supports the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Strategic Forces Command',\n", + " 'description': 'An inter-service command of the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Andaman And Nicobar Command',\n", + " 'description': 'An inter-service command of the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Integrated Defence Staff',\n", + " 'description': 'An inter-service command of the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Ministry Of Defence',\n", + " 'description': 'Manages the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Global Firepower Index',\n", + " 'description': 'Ranks the military forces globally.',\n", + " 'type': 'Report'},\n", + " {'id': 'Armed Forces Flag Day',\n", + " 'description': 'Honors armed forces and military personnel annually.',\n", + " 'type': 'Event'},\n", + " {'id': 'Mauryan Empire',\n", + " 'description': 'An ancient Indian empire known for its powerful military.',\n", + " 'type': 'Empire'},\n", + " {'id': 'Chola Empire',\n", + " 'description': 'Known for foreign trade and maritime activity.',\n", + " 'type': 'Empire'}],\n", + " 'rels': [{'start': 'Prime Minister Of India',\n", + " 'description': None,\n", + " 'type': 'EXECUTIVE_AUTHORITY',\n", + " 'end': 'Indian Armed Forces'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Indian Army'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Indian Navy'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Indian Air Force'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'SUPPORTED_BY',\n", + " 'end': 'Central Armed Police Forces'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'SUPPORTED_BY',\n", + " 'end': 'Indian Coast Guard'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'SUPPORTED_BY',\n", + " 'end': 'Special Frontier Force'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'SUPPORTED_BY',\n", + " 'end': 'Strategic Forces Command'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'SUPPORTED_BY',\n", + " 'end': 'Andaman And Nicobar Command'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'SUPPORTED_BY',\n", + " 'end': 'Integrated Defence Staff'},\n", + " {'start': 'Ministry Of Defence',\n", + " 'description': None,\n", + " 'type': 'MANAGES',\n", + " 'end': 'Indian Armed Forces'},\n", + " {'start': 'Global Firepower Index',\n", + " 'description': None,\n", + " 'type': 'RANKS',\n", + " 'end': 'Indian Armed Forces'},\n", + " {'start': 'Armed Forces Flag Day',\n", + " 'description': None,\n", + " 'type': 'HONORS',\n", + " 'end': 'Indian Armed Forces'},\n", + " {'start': 'Mauryan Empire',\n", + " 'description': None,\n", + " 'type': 'HISTORICAL_REFERENCE',\n", + " 'end': 'Indian Armed Forces'},\n", + " {'start': 'Chola Empire',\n", + " 'description': None,\n", + " 'type': 'HISTORICAL_REFERENCE',\n", + " 'end': 'Indian Armed Forces'}]},\n", + " {'communityId': '0-27',\n", + " 'nodes': [{'id': 'Rajya Sabha',\n", + " 'description': 'The mostly indirectly elected upper house of Parliament.',\n", + " 'type': 'Government body'},\n", + " {'id': 'Lok Sabha',\n", + " 'description': 'The directly elected lower house of Parliament.',\n", + " 'type': 'Government body'},\n", + " {'id': 'Union Council Of Ministers',\n", + " 'description': 'The executive decision-making committee of the government.',\n", + " 'type': 'Government body'}],\n", + " 'rels': [{'start': 'Union Council Of Ministers',\n", + " 'description': None,\n", + " 'type': 'RESPONSIBLE_TO',\n", + " 'end': 'Rajya Sabha'},\n", + " {'start': 'Union Council Of Ministers',\n", + " 'description': None,\n", + " 'type': 'RESPONSIBLE_TO',\n", + " 'end': 'Lok Sabha'}]},\n", + " {'communityId': '0-11',\n", + " 'nodes': [{'id': 'Republic Of India',\n", + " 'description': 'Has two principal official short names, India and Bharat.',\n", + " 'type': 'Country'},\n", + " {'id': 'Hindustan',\n", + " 'description': 'Commonly used name for the Republic of India.',\n", + " 'type': 'Name'}],\n", + " 'rels': [{'start': 'Republic Of India',\n", + " 'description': None,\n", + " 'type': 'HAS_NAME',\n", + " 'end': 'Hindustan'}]},\n", + " {'communityId': '0-15',\n", + " 'nodes': [{'id': 'Bharat',\n", + " 'description': 'Another principal official short name of the Republic of India.',\n", + " 'type': 'Name'},\n", + " {'id': 'Dushyanta',\n", + " 'description': 'Father of Bharata, associated with the name Bhāratavarṣa.',\n", + " 'type': 'Person'},\n", + " {'id': 'Mahabharata',\n", + " 'description': 'Epic associated with the name Bharata.',\n", + " 'type': 'Literature'}],\n", + " 'rels': [{'start': 'Bharat',\n", + " 'description': None,\n", + " 'type': 'ASSOCIATED_WITH',\n", + " 'end': 'Dushyanta'},\n", + " {'start': 'Bharat',\n", + " 'description': None,\n", + " 'type': 'ASSOCIATED_WITH',\n", + " 'end': 'Mahabharata'}]},\n", + " {'communityId': '0-14',\n", + " 'nodes': [{'id': 'Bhāratavarṣa',\n", + " 'description': 'Term used in the first century AD, derived from the name of the Vedic community of Bharatas.',\n", + " 'type': 'Historical term'},\n", + " {'id': 'Bharatas',\n", + " 'description': 'Mentioned in the Rigveda as one of the principal kingdoms of the Aryavarta.',\n", + " 'type': 'Vedic community'}],\n", + " 'rels': [{'start': 'Bhāratavarṣa',\n", + " 'description': None,\n", + " 'type': 'DERIVED_FROM',\n", + " 'end': 'Bharatas'}]},\n", + " {'communityId': '0-39',\n", + " 'nodes': [{'id': 'Thailand',\n", + " 'description': \"Shares maritime borders with India's Andaman and Nicobar Islands.\",\n", + " 'type': 'Country'},\n", + " {'id': 'Indonesia',\n", + " 'description': \"Shares maritime borders with India's Andaman and Nicobar Islands.\",\n", + " 'type': 'Country'},\n", + " {'id': 'Andaman And Nicobar Islands',\n", + " 'description': 'Islands of India sharing a maritime border with Thailand, Myanmar, and Indonesia.',\n", + " 'type': 'Island'}],\n", + " 'rels': [{'start': 'Andaman And Nicobar Islands',\n", + " 'description': None,\n", + " 'type': 'MARITIME_BORDER',\n", + " 'end': 'Thailand'},\n", + " {'start': 'Andaman And Nicobar Islands',\n", + " 'description': None,\n", + " 'type': 'MARITIME_BORDER',\n", + " 'end': 'Indonesia'}]},\n", + " {'communityId': '0-52',\n", + " 'nodes': [{'id': 'Constituent Assembly Of India',\n", + " 'description': 'Adopted the Constitution of India on 26 November 1949.',\n", + " 'type': 'Institution'},\n", + " {'id': 'Sardar Patel',\n", + " 'description': 'Convinced princely states to sign articles of integration with India.',\n", + " 'type': 'Person'},\n", + " {'id': 'V. P. Menon',\n", + " 'description': 'Convinced princely states to sign articles of integration with India.',\n", + " 'type': 'Person'}],\n", + " 'rels': [{'start': 'Sardar Patel',\n", + " 'description': 'Convinced princely states to sign articles of integration.',\n", + " 'type': 'CONVINCED',\n", + " 'end': 'Constituent Assembly Of India'},\n", + " {'start': 'V. P. Menon',\n", + " 'description': 'Convinced princely states to sign articles of integration.',\n", + " 'type': 'CONVINCED',\n", + " 'end': 'Constituent Assembly Of India'}]},\n", + " {'communityId': '0-78',\n", + " 'nodes': [{'id': 'Fauna Species',\n", + " 'description': 'India has an estimated 92,873 species of fauna.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Insects',\n", + " 'description': 'Major category with 63,423 recorded species.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Mammals Count',\n", + " 'description': '423 mammals in India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Birds Count',\n", + " 'description': '1,233 birds in India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Reptiles Count',\n", + " 'description': '526 reptiles in India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Amphibians Count',\n", + " 'description': '342 amphibians in India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Fish Count',\n", + " 'description': '3,022 fish in India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Endemic Mammals',\n", + " 'description': '12.6% of mammals are endemic to India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Endemic Birds',\n", + " 'description': '4.5% of birds are endemic to India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Endemic Reptiles',\n", + " 'description': '45.8% of reptiles are endemic to India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Endemic Amphibians',\n", + " 'description': '55.8% of amphibians are endemic to India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Large Animals',\n", + " 'description': 'Includes Indian elephant, Indian rhinoceros, and Gaur.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Big Cats',\n", + " 'description': 'Includes tiger and lion.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Cat Family',\n", + " 'description': 'Includes Bengal tiger, Asiatic lion, Indian leopard, snow leopard, and clouded leopard.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Representative Species',\n", + " 'description': 'Includes blackbuck, nilgai, bharal, barasingha, Nilgiri tahr, and Nilgiri langur.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Aquatic Mammals',\n", + " 'description': 'Includes dolphins, whales, porpoises, and dugong.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Reptiles Species',\n", + " 'description': 'Includes gharial and saltwater crocodiles.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Birds Species',\n", + " 'description': 'Includes peafowl, pheasants, geese, ducks, mynas, parakeets, pigeons, cranes, hornbills, and sunbirds.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Endemic Bird Species',\n", + " 'description': 'Includes great Indian hornbill, great Indian bustard, nicobar pigeon, ruddy shelduck, Himalayan monal, and Himalayan quail.',\n", + " 'type': 'Fauna'}],\n", + " 'rels': [{'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Insects'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Mammals Count'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Birds Count'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Reptiles Count'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Amphibians Count'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Fish Count'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Endemic Mammals'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Endemic Birds'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Endemic Reptiles'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Endemic Amphibians'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Large Animals'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Big Cats'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Cat Family'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Representative Species'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Aquatic Mammals'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Reptiles Species'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Birds Species'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Endemic Bird Species'}]},\n", + " {'communityId': '0-110',\n", + " 'nodes': [{'id': 'Plant Species',\n", + " 'description': 'About 29,015 species of plants.',\n", + " 'type': 'Flora'},\n", + " {'id': 'Flowering Plants Count',\n", + " 'description': '17,926 species of flowering plants.',\n", + " 'type': 'Flora'},\n", + " {'id': 'Endemic Plant Species',\n", + " 'description': '6,842 species are endemic to India.',\n", + " 'type': 'Flora'},\n", + " {'id': 'Algae', 'description': '7,244 species.', 'type': 'Flora'},\n", + " {'id': 'Bryophytes', 'description': '2,504 species.', 'type': 'Flora'},\n", + " {'id': 'Pteridophytes', 'description': '1,267 species.', 'type': 'Flora'},\n", + " {'id': 'Gymnosperms', 'description': '74 species.', 'type': 'Flora'},\n", + " {'id': 'Fungal Diversity',\n", + " 'description': 'Over 27,000 recorded species.',\n", + " 'type': 'Flora'},\n", + " {'id': 'Flora', 'description': None, 'type': None}],\n", + " 'rels': [{'start': 'Flora',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Plant Species'},\n", + " {'start': 'Flora',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Flowering Plants Count'},\n", + " {'start': 'Flora',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Endemic Plant Species'},\n", + " {'start': 'Flora', 'description': None, 'type': 'INCLUDES', 'end': 'Algae'},\n", + " {'start': 'Flora',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Bryophytes'},\n", + " {'start': 'Flora',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Pteridophytes'},\n", + " {'start': 'Flora',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Gymnosperms'},\n", + " {'start': 'Flora',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Fungal Diversity'}]},\n", + " {'communityId': '0-105',\n", + " 'nodes': [{'id': 'Threatened Species',\n", + " 'description': '172 IUCN-designated threatened species.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Threatened Mammals',\n", + " 'description': '39 species of mammals.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Threatened Birds',\n", + " 'description': '72 species of birds.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Threatened Reptiles',\n", + " 'description': '17 species of reptiles.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Threatened Amphibians',\n", + " 'description': '3 species of amphibians.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Threatened Fish',\n", + " 'description': '2 species of fish.',\n", + " 'type': 'Fauna'}],\n", + " 'rels': [{'start': 'Threatened Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Threatened Mammals'},\n", + " {'start': 'Threatened Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Threatened Birds'},\n", + " {'start': 'Threatened Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Threatened Reptiles'},\n", + " {'start': 'Threatened Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Threatened Amphibians'},\n", + " {'start': 'Threatened Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Threatened Fish'}]},\n", + " {'communityId': '0-125',\n", + " 'nodes': [{'id': 'Department Of Defence Production',\n", + " 'description': 'Responsible for indigenous production of equipment for the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Make In India Initiative',\n", + " 'description': 'Seeks to indigenise manufacturing and reduce dependence on imports for defence.',\n", + " 'type': 'Program'}],\n", + " 'rels': [{'start': 'Make In India Initiative',\n", + " 'description': None,\n", + " 'type': 'SUPPORTS',\n", + " 'end': 'Department Of Defence Production'}]},\n", + " {'communityId': '0-169',\n", + " 'nodes': [{'id': 'Maurya Empire',\n", + " 'description': 'Ancient empire based in the Ganges Basin.',\n", + " 'type': 'Empire'},\n", + " {'id': 'Gupta Empire',\n", + " 'description': 'Ancient empire based in the Ganges Basin.',\n", + " 'type': 'Empire'},\n", + " {'id': 'Ganges Basin', 'description': None, 'type': None}],\n", + " 'rels': [{'start': 'Ganges Basin',\n", + " 'description': None,\n", + " 'type': 'BASED_IN',\n", + " 'end': 'Maurya Empire'},\n", + " {'start': 'Ganges Basin',\n", + " 'description': None,\n", + " 'type': 'BASED_IN',\n", + " 'end': 'Gupta Empire'}]},\n", + " {'communityId': '0-170',\n", + " 'nodes': [{'id': 'Vijayanagara Empire',\n", + " 'description': 'Empire in south India that created a composite Hindu culture.',\n", + " 'type': 'Empire'},\n", + " {'id': 'South India', 'description': None, 'type': None}],\n", + " 'rels': [{'start': 'South India',\n", + " 'description': None,\n", + " 'type': 'BASED_IN',\n", + " 'end': 'Vijayanagara Empire'}]},\n", + " {'communityId': '0-171',\n", + " 'nodes': [{'id': 'Sikhism',\n", + " 'description': 'Religion that emerged in the Punjab, rejecting institutionalised religion.',\n", + " 'type': 'Religion'},\n", + " {'id': 'Punjab', 'description': None, 'type': None}],\n", + " 'rels': [{'start': 'Punjab',\n", + " 'description': None,\n", + " 'type': 'ORIGIN_OF',\n", + " 'end': 'Sikhism'}]},\n", + " {'communityId': '0-167',\n", + " 'nodes': [{'id': 'British East India Company',\n", + " 'description': 'Company that expanded rule in India, turning it into a colonial economy.',\n", + " 'type': 'Company'},\n", + " {'id': 'British Crown',\n", + " 'description': 'Began rule in India in 1858.',\n", + " 'type': 'Government'},\n", + " {'id': 'Indian Independence',\n", + " 'description': 'Event in 1947 when India was partitioned into two independent dominions.',\n", + " 'type': 'Event'}],\n", + " 'rels': [{'start': 'British East India Company',\n", + " 'description': None,\n", + " 'type': 'HISTORICAL_EVENT',\n", + " 'end': 'British Crown'},\n", + " {'start': 'British Crown',\n", + " 'description': None,\n", + " 'type': 'HISTORICAL_EVENT',\n", + " 'end': 'Indian Independence'}]},\n", + " {'communityId': '1-23',\n", + " 'nodes': [{'id': 'India',\n", + " 'description': 'Officially the Republic of India, located in South Asia.',\n", + " 'type': 'Country'},\n", + " {'id': 'Supreme Court Of India',\n", + " 'description': 'Head of the independent judiciary.',\n", + " 'type': 'Judiciary'},\n", + " {'id': 'Indian National Congress',\n", + " 'description': 'Dominated Indian politics until 1977.',\n", + " 'type': 'Political party'},\n", + " {'id': 'Sindhu',\n", + " 'description': 'Name of the Indus River, from which the name India is derived.',\n", + " 'type': 'River'},\n", + " {'id': 'Food And Agriculture Organization Of The United Nations',\n", + " 'description': \"Estimates India's forest cover.\",\n", + " 'type': 'Organization'},\n", + " {'id': '2013 Forest Survey Of India',\n", + " 'description': \"States India's forest cover increased to 69.8 million hectares by 2012.\",\n", + " 'type': 'Report'},\n", + " {'id': 'Yajnavalkya Smriti',\n", + " 'description': 'Prohibited the cutting of trees.',\n", + " 'type': 'Literature'},\n", + " {'id': 'Kautalyas Arthashastra',\n", + " 'description': 'Discusses the need for forest administration.',\n", + " 'type': 'Literature'},\n", + " {'id': 'Crown Land (Encroachment) Ordinance',\n", + " 'description': \"Promulgated in 1840 targeting forests in Britain's Asian colonies.\",\n", + " 'type': 'Legislation'},\n", + " {'id': 'Indian Forest Act Of 1865',\n", + " 'description': \"Established the government's claims over forests.\",\n", + " 'type': 'Legislation'},\n", + " {'id': 'Forest Act Of 1878',\n", + " 'description': 'Gave the British government control over all wastelands, including forests.',\n", + " 'type': 'Legislation'},\n", + " {'id': 'Sir Dietrich Brandis',\n", + " 'description': 'Inspector General of Forests in India from 1864 to 1883.',\n", + " 'type': 'Person'},\n", + " {'id': 'Indian Ocean',\n", + " 'description': 'Ocean bounded by India on the north.',\n", + " 'type': 'Ocean'},\n", + " {'id': 'Sri Lanka',\n", + " 'description': 'Country in the vicinity of India in the Indian Ocean.',\n", + " 'type': 'Country'},\n", + " {'id': 'Maldives',\n", + " 'description': 'Country in the vicinity of India in the Indian Ocean.',\n", + " 'type': 'Country'},\n", + " {'id': 'Myanmar',\n", + " 'description': 'Country sharing land border with India to the east.',\n", + " 'type': 'Country'},\n", + " {'id': 'Himalayan Mountain Range',\n", + " 'description': 'Defines the northern frontiers of India.',\n", + " 'type': 'Mountain range'},\n", + " {'id': 'China',\n", + " 'description': 'Country sharing land border with India to the north.',\n", + " 'type': 'Country'},\n", + " {'id': 'Bhutan',\n", + " 'description': 'Country sharing land border with India to the north.',\n", + " 'type': 'Country'},\n", + " {'id': 'Nepal',\n", + " 'description': 'Country sharing land border with India to the north.',\n", + " 'type': 'Country'},\n", + " {'id': 'Pakistan',\n", + " 'description': 'Country sharing land border with India to the west.',\n", + " 'type': 'Country'},\n", + " {'id': 'Bangladesh',\n", + " 'description': 'Country sharing land border with India to the east.',\n", + " 'type': 'Country'},\n", + " {'id': 'Ganges',\n", + " 'description': 'The longest river originating in India.',\n", + " 'type': 'River'},\n", + " {'id': 'Western Ghats',\n", + " 'description': 'One of the three biodiversity hotspots in India.',\n", + " 'type': 'Biodiversity hotspot'},\n", + " {'id': 'Eastern Himalayas',\n", + " 'description': 'One of the three biodiversity hotspots in India.',\n", + " 'type': 'Biodiversity hotspot'},\n", + " {'id': 'Indo-Burma Hotspot',\n", + " 'description': 'One of the three biodiversity hotspots in India.',\n", + " 'type': 'Biodiversity hotspot'},\n", + " {'id': 'Forests',\n", + " 'description': 'Covers about 24.6% of the total land area.',\n", + " 'type': 'Ecosystem'},\n", + " {'id': 'Indomalayan Realm',\n", + " 'description': 'Geographical realm that includes India.',\n", + " 'type': 'Realm'},\n", + " {'id': 'World', 'description': None, 'type': None},\n", + " {'id': 'Public_Sector', 'description': None, 'type': None},\n", + " {'id': 'Gdp', 'description': None, 'type': None},\n", + " {'id': 'Economic_Liberalisation', 'description': None, 'type': None},\n", + " {'id': 'Gdp_Growth', 'description': None, 'type': None},\n", + " {'id': 'Consumer_Market', 'description': None, 'type': None},\n", + " {'id': 'Wto', 'description': None, 'type': None},\n", + " {'id': 'Ease_Of_Business_Index', 'description': None, 'type': None},\n", + " {'id': 'Global_Competitiveness_Index', 'description': None, 'type': None},\n", + " {'id': 'Billionaires', 'description': None, 'type': None},\n", + " {'id': 'Welfare_State', 'description': None, 'type': None},\n", + " {'id': 'Socialist_State', 'description': None, 'type': None},\n", + " {'id': 'Social_Welfare_Spending', 'description': None, 'type': None},\n", + " {'id': 'Labour_Force', 'description': None, 'type': None},\n", + " {'id': 'Fdi', 'description': None, 'type': None},\n", + " {'id': 'Free_Trade_Agreements', 'description': None, 'type': None},\n", + " {'id': 'Service_Sector', 'description': None, 'type': None},\n", + " {'id': 'Stock_Exchanges', 'description': None, 'type': None},\n", + " {'id': 'Manufacturing', 'description': None, 'type': None},\n", + " {'id': 'Population', 'description': None, 'type': None},\n", + " {'id': 'Unemployment', 'description': None, 'type': None},\n", + " {'id': 'Savings_Rate', 'description': None, 'type': None},\n", + " {'id': 'Arabian Sea',\n", + " 'description': 'Sea bounded by India on the northwest.',\n", + " 'type': 'Sea'},\n", + " {'id': 'Bay Of Bengal',\n", + " 'description': 'Bay bounded by India on the southeast.',\n", + " 'type': 'Bay'},\n", + " {'id': 'Africa',\n", + " 'description': 'Continent from which modern humans arrived on the Indian subcontinent.',\n", + " 'type': 'Continent'},\n", + " {'id': 'Indus Valley Civilisation',\n", + " 'description': 'Civilisation that evolved from settled life in the western margins of the Indus river basin.',\n", + " 'type': 'Civilization'},\n", + " {'id': 'Sanskrit',\n", + " 'description': 'Indo-European language that diffused into India from the northwest.',\n", + " 'type': 'Language'},\n", + " {'id': 'Rigveda',\n", + " 'description': 'Ancient hymns recording the dawning of Hinduism in India.',\n", + " 'type': 'Text'},\n", + " {'id': 'Hinduism',\n", + " 'description': 'Major religion in India, with roots in the Rigveda.',\n", + " 'type': 'Religion'},\n", + " {'id': 'Buddhism',\n", + " 'description': 'Religion that arose in India, proclaiming social orders unlinked to heredity.',\n", + " 'type': 'Religion'},\n", + " {'id': 'Jainism',\n", + " 'description': 'Religion that arose in India, proclaiming social orders unlinked to heredity.',\n", + " 'type': 'Religion'},\n", + " {'id': 'Mughal Empire',\n", + " 'description': 'Empire that began in 1526, known for its architecture and relative peace.',\n", + " 'type': 'Empire'},\n", + " {'id': 'Indian Republic',\n", + " 'description': 'India has been a federal republic since 1950.',\n", + " 'type': 'Government'},\n", + " {'id': 'Thailand',\n", + " 'description': \"Shares maritime borders with India's Andaman and Nicobar Islands.\",\n", + " 'type': 'Country'},\n", + " {'id': 'Indonesia',\n", + " 'description': \"Shares maritime borders with India's Andaman and Nicobar Islands.\",\n", + " 'type': 'Country'},\n", + " {'id': 'Andaman And Nicobar Islands',\n", + " 'description': 'Islands of India sharing a maritime border with Thailand, Myanmar, and Indonesia.',\n", + " 'type': 'Island'}],\n", + " 'rels': [{'start': 'India',\n", + " 'description': None,\n", + " 'type': 'IS_PART_OF',\n", + " 'end': 'Indomalayan Realm'},\n", + " {'start': 'India',\n", + " 'description': 'About 1,900 public sector companies with complete control and ownership of railways, highways, and majority control in various industries.',\n", + " 'type': 'HAS',\n", + " 'end': 'Public_Sector'},\n", + " {'start': 'India',\n", + " 'description': \"One of the world's highest number of billionaires.\",\n", + " 'type': 'HAS',\n", + " 'end': 'Billionaires'},\n", + " {'start': 'India',\n", + " 'description': \"World's second-largest labour force with 586 million workers.\",\n", + " 'type': 'HAS',\n", + " 'end': 'Labour_Force'},\n", + " {'start': 'India',\n", + " 'description': 'Has free trade agreements with several nations and blocs.',\n", + " 'type': 'HAS',\n", + " 'end': 'Free_Trade_Agreements'},\n", + " {'start': 'India',\n", + " 'description': \"Bombay Stock Exchange and National Stock Exchange are among the world's largest stock exchanges.\",\n", + " 'type': 'HAS',\n", + " 'end': 'Stock_Exchanges'},\n", + " {'start': 'India',\n", + " 'description': \"Nearly 65% of India's population is rural.\",\n", + " 'type': 'HAS',\n", + " 'end': 'Population'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'RELATES_TO',\n", + " 'end': 'Rigveda'},\n", + " {'start': 'India',\n", + " 'description': 'Member of the World Trade Organization since 1 January 1995.',\n", + " 'type': 'MEMBER_OF',\n", + " 'end': 'Wto'},\n", + " {'start': 'India',\n", + " 'description': 'High unemployment and rising income inequality.',\n", + " 'type': 'FACES',\n", + " 'end': 'Unemployment'},\n", + " {'start': 'India',\n", + " 'description': 'Adopted broad economic liberalisation in 1991.',\n", + " 'type': 'ADOPTED',\n", + " 'end': 'Economic_Liberalisation'},\n", + " {'start': 'India',\n", + " 'description': 'Often considered a welfare state.',\n", + " 'type': 'CONSIDERED_AS',\n", + " 'end': 'Welfare_State'},\n", + " {'start': 'India', 'description': None, 'type': 'NEAR', 'end': 'Sri Lanka'},\n", + " {'start': 'India', 'description': None, 'type': 'NEAR', 'end': 'Maldives'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'BORDERS',\n", + " 'end': 'Indian Ocean'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'BORDERS',\n", + " 'end': 'Myanmar'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'BORDERS',\n", + " 'end': 'Himalayan Mountain Range'},\n", + " {'start': 'India', 'description': None, 'type': 'BORDERS', 'end': 'China'},\n", + " {'start': 'India', 'description': None, 'type': 'BORDERS', 'end': 'Bhutan'},\n", + " {'start': 'India', 'description': None, 'type': 'BORDERS', 'end': 'Nepal'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'BORDERS',\n", + " 'end': 'Pakistan'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'BORDERS',\n", + " 'end': 'Bangladesh'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'BORDERS',\n", + " 'end': 'Arabian Sea'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'BORDERS',\n", + " 'end': 'Bay Of Bengal'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'SEPARATED_BY',\n", + " 'end': 'Sri Lanka'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'DERIVED_FROM',\n", + " 'end': 'Sindhu'},\n", + " {'start': 'India',\n", + " 'description': \"Estimates India's forest cover.\",\n", + " 'type': 'ESTIMATES',\n", + " 'end': 'Food And Agriculture Organization Of The United Nations'},\n", + " {'start': 'India',\n", + " 'description': 'Makes up more than 50% of GDP.',\n", + " 'type': 'MAKES_UP',\n", + " 'end': 'Service_Sector'},\n", + " {'start': 'India',\n", + " 'description': 'Fifth-largest economy by nominal GDP and third-largest by purchasing power parity (PPP).',\n", + " 'type': 'RANKS_AS',\n", + " 'end': 'World'},\n", + " {'start': 'India',\n", + " 'description': 'Fourth-largest consumer market in the world.',\n", + " 'type': 'RANKS_AS',\n", + " 'end': 'Consumer_Market'},\n", + " {'start': 'India',\n", + " 'description': \"World's sixth-largest manufacturer, representing 2.6% of global manufacturing output.\",\n", + " 'type': 'RANKS_AS',\n", + " 'end': 'Manufacturing'},\n", + " {'start': 'India',\n", + " 'description': 'Officially declared a socialist state as per the constitution.',\n", + " 'type': 'DECLARED_AS',\n", + " 'end': 'Socialist_State'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'ORIGIN_OF',\n", + " 'end': 'Hinduism'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'ORIGIN_OF',\n", + " 'end': 'Buddhism'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'ORIGIN_OF',\n", + " 'end': 'Jainism'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'GOVERNED_AS',\n", + " 'end': 'Indian Republic'},\n", + " {'start': 'India',\n", + " 'description': '136th by GDP (nominal) and 125th by GDP (PPP) on a per capita income basis.',\n", + " 'type': 'RANKS',\n", + " 'end': 'Gdp'},\n", + " {'start': 'India',\n", + " 'description': '63rd on the Ease of Doing Business index.',\n", + " 'type': 'RANKS',\n", + " 'end': 'Ease_Of_Business_Index'},\n", + " {'start': 'India',\n", + " 'description': '40th on the Global Competitiveness Index.',\n", + " 'type': 'RANKS',\n", + " 'end': 'Global_Competitiveness_Index'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'SHARES_BORDERS_WITH',\n", + " 'end': 'Myanmar'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'SHARES_BORDERS_WITH',\n", + " 'end': 'Thailand'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'SHARES_BORDERS_WITH',\n", + " 'end': 'Indonesia'},\n", + " {'start': 'India',\n", + " 'description': 'Overall social welfare spending stood at 8.6% of GDP in 2021-22.',\n", + " 'type': 'SPENDING',\n", + " 'end': 'Social_Welfare_Spending'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'HISTORICAL_EVENT',\n", + " 'end': 'Mughal Empire'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'ORIGINATES_IN',\n", + " 'end': 'Ganges'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'HAS_BIODIVERSITY_HOTSPOT',\n", + " 'end': 'Western Ghats'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'HAS_BIODIVERSITY_HOTSPOT',\n", + " 'end': 'Eastern Himalayas'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'HAS_BIODIVERSITY_HOTSPOT',\n", + " 'end': 'Indo-Burma Hotspot'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'HAS_ECOSYSTEM',\n", + " 'end': 'Forests'},\n", + " {'start': 'India',\n", + " 'description': '6% to 7% since the start of the 21st century.',\n", + " 'type': 'AVERAGE_ANNUAL_GROWTH',\n", + " 'end': 'Gdp_Growth'},\n", + " {'start': 'India',\n", + " 'description': 'Foreign direct investment in 2021-22 was $82 billion.',\n", + " 'type': 'FOREIGN_DIRECT_INVESTMENT',\n", + " 'end': 'Fdi'},\n", + " {'start': 'India',\n", + " 'description': 'Gross domestic savings rate stood at 29.3% of GDP in 2022.',\n", + " 'type': 'GROSS_DOMESTIC_SAVINGS_RATE',\n", + " 'end': 'Savings_Rate'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'HUMAN_ORIGIN',\n", + " 'end': 'Africa'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'HISTORICAL_DEVELOPMENT',\n", + " 'end': 'Indus Valley Civilisation'},\n", + " {'start': 'India',\n", + " 'description': None,\n", + " 'type': 'LANGUAGE_DIFFUSION',\n", + " 'end': 'Sanskrit'},\n", + " {'start': 'Kautalyas Arthashastra',\n", + " 'description': 'Discusses the need for forest administration.',\n", + " 'type': 'DISCUSSES',\n", + " 'end': 'India'},\n", + " {'start': 'Indian Forest Act Of 1865',\n", + " 'description': \"Establishes government's claims over forests.\",\n", + " 'type': 'ESTABLISHES',\n", + " 'end': 'India'},\n", + " {'start': 'Crown Land (Encroachment) Ordinance',\n", + " 'description': \"Targets forests in Britain's Asian colonies.\",\n", + " 'type': 'TARGETS',\n", + " 'end': 'India'},\n", + " {'start': 'Yajnavalkya Smriti',\n", + " 'description': 'Prohibits the cutting of trees.',\n", + " 'type': 'PROHIBITS',\n", + " 'end': 'India'},\n", + " {'start': '2013 Forest Survey Of India',\n", + " 'description': 'Reports on forest cover increase.',\n", + " 'type': 'REPORTS_ON',\n", + " 'end': 'India'},\n", + " {'start': 'Supreme Court Of India',\n", + " 'description': None,\n", + " 'type': 'PART_OF_JUDICIARY',\n", + " 'end': 'India'},\n", + " {'start': 'Indian National Congress',\n", + " 'description': None,\n", + " 'type': 'HISTORICALLY_DOMINANT_PARTY',\n", + " 'end': 'India'},\n", + " {'start': 'Forest Act Of 1878',\n", + " 'description': 'Gives control over all wastelands, including forests.',\n", + " 'type': 'GIVES_CONTROL',\n", + " 'end': 'India'},\n", + " {'start': 'Sir Dietrich Brandis',\n", + " 'description': 'Inspector General of Forests in India from 1864 to 1883.',\n", + " 'type': 'INSPECTOR_GENERAL_OF',\n", + " 'end': 'India'},\n", + " {'start': 'Andaman And Nicobar Islands',\n", + " 'description': None,\n", + " 'type': 'MARITIME_BORDER',\n", + " 'end': 'Myanmar'},\n", + " {'start': 'Andaman And Nicobar Islands',\n", + " 'description': None,\n", + " 'type': 'MARITIME_BORDER',\n", + " 'end': 'Thailand'},\n", + " {'start': 'Andaman And Nicobar Islands',\n", + " 'description': None,\n", + " 'type': 'MARITIME_BORDER',\n", + " 'end': 'Indonesia'}]},\n", + " {'communityId': '1-7',\n", + " 'nodes': [{'id': 'Constitution Of India',\n", + " 'description': 'The supreme law of India, laying down the framework for government institutions and fundamental rights.',\n", + " 'type': 'Document'},\n", + " {'id': 'Parliament',\n", + " 'description': 'Cannot override the Constitution of India.',\n", + " 'type': 'Institution'},\n", + " {'id': 'Government Of India Act 1935',\n", + " 'description': 'Replaced by the Constitution of India.',\n", + " 'type': 'Document'},\n", + " {'id': 'Constituent Assembly',\n", + " 'description': 'Tasked with drafting the Constitution of India.',\n", + " 'type': 'Government body'},\n", + " {'id': 'M. N. Roy',\n", + " 'description': 'Proposed the framework for the Constitution of India.',\n", + " 'type': 'Person'},\n", + " {'id': 'Republic Day',\n", + " 'description': 'Celebrated on 26 January in India to honor the Constitution.',\n", + " 'type': 'Event'},\n", + " {'id': 'Old Parliament House',\n", + " 'description': 'Preserves the original 1950 Constitution in a nitrogen-filled case.',\n", + " 'type': 'Location'},\n", + " {'id': 'British Government',\n", + " 'description': 'Responsible for the external security of India during its dominion status.',\n", + " 'type': 'Institution'},\n", + " {'id': 'Indian Independence Act 1947',\n", + " 'description': 'Repealed by the Constitution of India.',\n", + " 'type': 'Document'},\n", + " {'id': 'Articles Of The Constitution',\n", + " 'description': 'Articles 5, 6, 7, 8, 9, 60, 324, 366, 367, 379, 380, 388, 391, 392, 393, and 394 came into force on 26 November 1949.',\n", + " 'type': 'Document'},\n", + " {'id': 'Constituent Assembly Of India',\n", + " 'description': 'Adopted the Constitution of India on 26 November 1949.',\n", + " 'type': 'Institution'},\n", + " {'id': 'Sardar Patel',\n", + " 'description': 'Convinced princely states to sign articles of integration with India.',\n", + " 'type': 'Person'},\n", + " {'id': 'V. P. Menon',\n", + " 'description': 'Convinced princely states to sign articles of integration with India.',\n", + " 'type': 'Person'}],\n", + " 'rels': [{'start': 'Constitution Of India',\n", + " 'description': 'The Constitution is based on the proposal suggested by M. N. Roy.',\n", + " 'type': 'BASED_ON',\n", + " 'end': 'M. N. Roy'},\n", + " {'start': 'Constitution Of India',\n", + " 'description': 'Adopted by the Constituent Assembly on 26 November 1949.',\n", + " 'type': 'ADOPTED_BY',\n", + " 'end': 'Constituent Assembly Of India'},\n", + " {'start': 'Constitution Of India',\n", + " 'description': 'The original 1950 Constitution is preserved in a nitrogen-filled case.',\n", + " 'type': 'PRESERVED_IN',\n", + " 'end': 'Old Parliament House'},\n", + " {'start': 'Constitution Of India',\n", + " 'description': 'Celebrated on 26 January.',\n", + " 'type': 'CELEBRATED_ON',\n", + " 'end': 'Republic Day'},\n", + " {'start': 'Constitution Of India',\n", + " 'description': 'Parliament cannot override the Constitution.',\n", + " 'type': 'CANNOT_OVERRIDE',\n", + " 'end': 'Parliament'},\n", + " {'start': 'Constitution Of India',\n", + " 'description': 'Certain articles came into force on 26 November 1949.',\n", + " 'type': 'CAME_INTO_FORCE',\n", + " 'end': 'Articles Of The Constitution'},\n", + " {'start': 'Government Of India Act 1935',\n", + " 'description': 'Replaced by the Constitution of India.',\n", + " 'type': 'REPLACED_BY',\n", + " 'end': 'Constitution Of India'},\n", + " {'start': 'British Government',\n", + " 'description': 'Responsible for the external security of India during its dominion status.',\n", + " 'type': 'RESPONSIBLE_FOR',\n", + " 'end': 'Constitution Of India'},\n", + " {'start': 'Indian Independence Act 1947',\n", + " 'description': 'Repealed by the Constitution of India.',\n", + " 'type': 'REPEALED_BY',\n", + " 'end': 'Constitution Of India'},\n", + " {'start': 'Constituent Assembly',\n", + " 'description': None,\n", + " 'type': 'DRAFTED_BY',\n", + " 'end': 'Constitution Of India'},\n", + " {'start': 'Sardar Patel',\n", + " 'description': 'Convinced princely states to sign articles of integration.',\n", + " 'type': 'CONVINCED',\n", + " 'end': 'Constituent Assembly Of India'},\n", + " {'start': 'V. P. Menon',\n", + " 'description': 'Convinced princely states to sign articles of integration.',\n", + " 'type': 'CONVINCED',\n", + " 'end': 'Constituent Assembly Of India'}]},\n", + " {'communityId': '1-4',\n", + " 'nodes': [{'id': 'President Of India',\n", + " 'description': 'The Supreme Commander of the Indian Armed Forces.',\n", + " 'type': 'Person'},\n", + " {'id': 'Nda',\n", + " 'description': 'A coalition of the BJP and its allies governing India since 2014.',\n", + " 'type': 'Political alliance'},\n", + " {'id': 'Government Of India',\n", + " 'description': 'Established a system of national parks and protected areas.',\n", + " 'type': 'Government'},\n", + " {'id': 'Narendra Modi',\n", + " 'description': 'Current Prime Minister of India since 26 May 2014.',\n", + " 'type': 'Person'},\n", + " {'id': 'New Delhi',\n", + " 'description': 'The seat of the Government of India.',\n", + " 'type': 'Location'},\n", + " {'id': 'Supreme Court',\n", + " 'description': 'The highest judicial forum and final court of appeal under the Constitution of India.',\n", + " 'type': 'Judiciary'},\n", + " {'id': 'Indian Councils Act 1909',\n", + " 'description': 'Introduced elections to the Imperial Legislative Council.',\n", + " 'type': 'Legislation'},\n", + " {'id': 'Government Of India Act 1919',\n", + " 'description': 'Expanded the Imperial Legislative Council.',\n", + " 'type': 'Legislation'},\n", + " {'id': 'National Parks',\n", + " 'description': 'Established in 1935 and expanded to nearly 1022 by 2023.',\n", + " 'type': 'Protected area'},\n", + " {'id': 'Wildlife Protection Act Of 1972',\n", + " 'description': 'Enacted for the protection of wildlife.',\n", + " 'type': 'Legislation'},\n", + " {'id': 'Project Tiger',\n", + " 'description': 'Special project for the protection of critical species.',\n", + " 'type': 'Conservation project'},\n", + " {'id': 'Project Elephant',\n", + " 'description': 'Special project for the protection of critical species.',\n", + " 'type': 'Conservation project'},\n", + " {'id': 'Project Dolphin',\n", + " 'description': 'Special project for the protection of critical species.',\n", + " 'type': 'Conservation project'},\n", + " {'id': 'Rajya Sabha',\n", + " 'description': 'The mostly indirectly elected upper house of Parliament.',\n", + " 'type': 'Government body'},\n", + " {'id': 'Lok Sabha',\n", + " 'description': 'The directly elected lower house of Parliament.',\n", + " 'type': 'Government body'},\n", + " {'id': 'Union Council Of Ministers',\n", + " 'description': 'The executive decision-making committee of the government.',\n", + " 'type': 'Government body'}],\n", + " 'rels': [{'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'INITIATED',\n", + " 'end': 'Project Tiger'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'INITIATED',\n", + " 'end': 'Project Elephant'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'INITIATED',\n", + " 'end': 'Project Dolphin'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'GOVERNED_BY',\n", + " 'end': 'Nda'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'COMPOSED_OF',\n", + " 'end': 'Union Council Of Ministers'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'ENACTED',\n", + " 'end': 'Wildlife Protection Act Of 1972'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'ESTABLISHED',\n", + " 'end': 'National Parks'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'LEAD_BY',\n", + " 'end': 'Narendra Modi'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'RESPONSIBLE_TO',\n", + " 'end': 'Supreme Court'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'SEATED_IN',\n", + " 'end': 'New Delhi'},\n", + " {'start': 'Government Of India',\n", + " 'description': None,\n", + " 'type': 'HEAD_OF_STATE',\n", + " 'end': 'President Of India'},\n", + " {'start': 'Indian Councils Act 1909',\n", + " 'description': None,\n", + " 'type': 'INFLUENCED',\n", + " 'end': 'Government Of India'},\n", + " {'start': 'Government Of India Act 1919',\n", + " 'description': None,\n", + " 'type': 'INFLUENCED',\n", + " 'end': 'Government Of India'},\n", + " {'start': 'Union Council Of Ministers',\n", + " 'description': None,\n", + " 'type': 'RESPONSIBLE_TO',\n", + " 'end': 'Rajya Sabha'},\n", + " {'start': 'Union Council Of Ministers',\n", + " 'description': None,\n", + " 'type': 'RESPONSIBLE_TO',\n", + " 'end': 'Lok Sabha'}]},\n", + " {'communityId': '1-22',\n", + " 'nodes': [{'id': 'Prime Minister Of India',\n", + " 'description': 'Holds executive authority and responsibility for national security.',\n", + " 'type': 'Person'},\n", + " {'id': 'Indian Armed Forces',\n", + " 'description': 'The military forces of the Republic of India.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Indian Army',\n", + " 'description': 'One of the three professional uniformed services of the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Indian Navy',\n", + " 'description': 'One of the three professional uniformed services of the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Indian Air Force',\n", + " 'description': 'One of the three professional uniformed services of the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Central Armed Police Forces',\n", + " 'description': 'Supports the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Indian Coast Guard',\n", + " 'description': 'Supports the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Special Frontier Force',\n", + " 'description': 'Supports the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Strategic Forces Command',\n", + " 'description': 'An inter-service command of the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Andaman And Nicobar Command',\n", + " 'description': 'An inter-service command of the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Integrated Defence Staff',\n", + " 'description': 'An inter-service command of the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Ministry Of Defence',\n", + " 'description': 'Manages the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Global Firepower Index',\n", + " 'description': 'Ranks the military forces globally.',\n", + " 'type': 'Report'},\n", + " {'id': 'Armed Forces Flag Day',\n", + " 'description': 'Honors armed forces and military personnel annually.',\n", + " 'type': 'Event'},\n", + " {'id': 'Mauryan Empire',\n", + " 'description': 'An ancient Indian empire known for its powerful military.',\n", + " 'type': 'Empire'},\n", + " {'id': 'Chola Empire',\n", + " 'description': 'Known for foreign trade and maritime activity.',\n", + " 'type': 'Empire'},\n", + " {'id': 'Department Of Defence Production',\n", + " 'description': 'Responsible for indigenous production of equipment for the Indian Armed Forces.',\n", + " 'type': 'Organization'},\n", + " {'id': 'Make In India Initiative',\n", + " 'description': 'Seeks to indigenise manufacturing and reduce dependence on imports for defence.',\n", + " 'type': 'Program'}],\n", + " 'rels': [{'start': 'Prime Minister Of India',\n", + " 'description': None,\n", + " 'type': 'EXECUTIVE_AUTHORITY',\n", + " 'end': 'Indian Armed Forces'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Indian Army'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Indian Navy'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Indian Air Force'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'SUPPORTED_BY',\n", + " 'end': 'Central Armed Police Forces'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'SUPPORTED_BY',\n", + " 'end': 'Indian Coast Guard'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'SUPPORTED_BY',\n", + " 'end': 'Special Frontier Force'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'SUPPORTED_BY',\n", + " 'end': 'Strategic Forces Command'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'SUPPORTED_BY',\n", + " 'end': 'Andaman And Nicobar Command'},\n", + " {'start': 'Indian Armed Forces',\n", + " 'description': None,\n", + " 'type': 'SUPPORTED_BY',\n", + " 'end': 'Integrated Defence Staff'},\n", + " {'start': 'Ministry Of Defence',\n", + " 'description': None,\n", + " 'type': 'MANAGES',\n", + " 'end': 'Indian Armed Forces'},\n", + " {'start': 'Global Firepower Index',\n", + " 'description': None,\n", + " 'type': 'RANKS',\n", + " 'end': 'Indian Armed Forces'},\n", + " {'start': 'Armed Forces Flag Day',\n", + " 'description': None,\n", + " 'type': 'HONORS',\n", + " 'end': 'Indian Armed Forces'},\n", + " {'start': 'Department Of Defence Production',\n", + " 'description': None,\n", + " 'type': 'PRODUCES_EQUIPMENT_FOR',\n", + " 'end': 'Indian Armed Forces'},\n", + " {'start': 'Mauryan Empire',\n", + " 'description': None,\n", + " 'type': 'HISTORICAL_REFERENCE',\n", + " 'end': 'Indian Armed Forces'},\n", + " {'start': 'Chola Empire',\n", + " 'description': None,\n", + " 'type': 'HISTORICAL_REFERENCE',\n", + " 'end': 'Indian Armed Forces'},\n", + " {'start': 'Make In India Initiative',\n", + " 'description': None,\n", + " 'type': 'SUPPORTS',\n", + " 'end': 'Department Of Defence Production'}]},\n", + " {'communityId': '1-2',\n", + " 'nodes': [{'id': 'Republic Of India',\n", + " 'description': 'Has two principal official short names, India and Bharat.',\n", + " 'type': 'Country'},\n", + " {'id': 'Hindustan',\n", + " 'description': 'Commonly used name for the Republic of India.',\n", + " 'type': 'Name'},\n", + " {'id': 'Bharat',\n", + " 'description': 'Another principal official short name of the Republic of India.',\n", + " 'type': 'Name'},\n", + " {'id': 'Dushyanta',\n", + " 'description': 'Father of Bharata, associated with the name Bhāratavarṣa.',\n", + " 'type': 'Person'},\n", + " {'id': 'Mahabharata',\n", + " 'description': 'Epic associated with the name Bharata.',\n", + " 'type': 'Literature'},\n", + " {'id': 'Bhāratavarṣa',\n", + " 'description': 'Term used in the first century AD, derived from the name of the Vedic community of Bharatas.',\n", + " 'type': 'Historical term'},\n", + " {'id': 'Bharatas',\n", + " 'description': 'Mentioned in the Rigveda as one of the principal kingdoms of the Aryavarta.',\n", + " 'type': 'Vedic community'}],\n", + " 'rels': [{'start': 'Republic Of India',\n", + " 'description': None,\n", + " 'type': 'HAS_NAME',\n", + " 'end': 'Bharat'},\n", + " {'start': 'Republic Of India',\n", + " 'description': None,\n", + " 'type': 'HAS_NAME',\n", + " 'end': 'Hindustan'},\n", + " {'start': 'Bharat',\n", + " 'description': None,\n", + " 'type': 'ASSOCIATED_WITH',\n", + " 'end': 'Dushyanta'},\n", + " {'start': 'Bharat',\n", + " 'description': None,\n", + " 'type': 'ASSOCIATED_WITH',\n", + " 'end': 'Mahabharata'},\n", + " {'start': 'Bharat',\n", + " 'description': None,\n", + " 'type': 'DERIVED_FROM',\n", + " 'end': 'Bhāratavarṣa'},\n", + " {'start': 'Bhāratavarṣa',\n", + " 'description': None,\n", + " 'type': 'DERIVED_FROM',\n", + " 'end': 'Bharatas'}]},\n", + " {'communityId': '1-18',\n", + " 'nodes': [{'id': 'Fauna Species',\n", + " 'description': 'India has an estimated 92,873 species of fauna.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Insects',\n", + " 'description': 'Major category with 63,423 recorded species.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Mammals Count',\n", + " 'description': '423 mammals in India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Birds Count',\n", + " 'description': '1,233 birds in India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Reptiles Count',\n", + " 'description': '526 reptiles in India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Amphibians Count',\n", + " 'description': '342 amphibians in India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Fish Count',\n", + " 'description': '3,022 fish in India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Endemic Mammals',\n", + " 'description': '12.6% of mammals are endemic to India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Endemic Birds',\n", + " 'description': '4.5% of birds are endemic to India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Endemic Reptiles',\n", + " 'description': '45.8% of reptiles are endemic to India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Endemic Amphibians',\n", + " 'description': '55.8% of amphibians are endemic to India.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Large Animals',\n", + " 'description': 'Includes Indian elephant, Indian rhinoceros, and Gaur.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Big Cats',\n", + " 'description': 'Includes tiger and lion.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Cat Family',\n", + " 'description': 'Includes Bengal tiger, Asiatic lion, Indian leopard, snow leopard, and clouded leopard.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Representative Species',\n", + " 'description': 'Includes blackbuck, nilgai, bharal, barasingha, Nilgiri tahr, and Nilgiri langur.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Aquatic Mammals',\n", + " 'description': 'Includes dolphins, whales, porpoises, and dugong.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Reptiles Species',\n", + " 'description': 'Includes gharial and saltwater crocodiles.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Birds Species',\n", + " 'description': 'Includes peafowl, pheasants, geese, ducks, mynas, parakeets, pigeons, cranes, hornbills, and sunbirds.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Endemic Bird Species',\n", + " 'description': 'Includes great Indian hornbill, great Indian bustard, nicobar pigeon, ruddy shelduck, Himalayan monal, and Himalayan quail.',\n", + " 'type': 'Fauna'}],\n", + " 'rels': [{'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Insects'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Mammals Count'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Birds Count'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Reptiles Count'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Amphibians Count'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Fish Count'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Endemic Mammals'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Endemic Birds'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Endemic Reptiles'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Endemic Amphibians'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Large Animals'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Big Cats'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Cat Family'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Representative Species'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Aquatic Mammals'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Reptiles Species'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Birds Species'},\n", + " {'start': 'Fauna Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Endemic Bird Species'}]},\n", + " {'communityId': '1-20',\n", + " 'nodes': [{'id': 'Plant Species',\n", + " 'description': 'About 29,015 species of plants.',\n", + " 'type': 'Flora'},\n", + " {'id': 'Flowering Plants Count',\n", + " 'description': '17,926 species of flowering plants.',\n", + " 'type': 'Flora'},\n", + " {'id': 'Endemic Plant Species',\n", + " 'description': '6,842 species are endemic to India.',\n", + " 'type': 'Flora'},\n", + " {'id': 'Algae', 'description': '7,244 species.', 'type': 'Flora'},\n", + " {'id': 'Bryophytes', 'description': '2,504 species.', 'type': 'Flora'},\n", + " {'id': 'Pteridophytes', 'description': '1,267 species.', 'type': 'Flora'},\n", + " {'id': 'Gymnosperms', 'description': '74 species.', 'type': 'Flora'},\n", + " {'id': 'Fungal Diversity',\n", + " 'description': 'Over 27,000 recorded species.',\n", + " 'type': 'Flora'},\n", + " {'id': 'Flora', 'description': None, 'type': None}],\n", + " 'rels': [{'start': 'Flora',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Plant Species'},\n", + " {'start': 'Flora',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Flowering Plants Count'},\n", + " {'start': 'Flora',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Endemic Plant Species'},\n", + " {'start': 'Flora', 'description': None, 'type': 'INCLUDES', 'end': 'Algae'},\n", + " {'start': 'Flora',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Bryophytes'},\n", + " {'start': 'Flora',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Pteridophytes'},\n", + " {'start': 'Flora',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Gymnosperms'},\n", + " {'start': 'Flora',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Fungal Diversity'}]},\n", + " {'communityId': '1-19',\n", + " 'nodes': [{'id': 'Threatened Species',\n", + " 'description': '172 IUCN-designated threatened species.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Threatened Mammals',\n", + " 'description': '39 species of mammals.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Threatened Birds',\n", + " 'description': '72 species of birds.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Threatened Reptiles',\n", + " 'description': '17 species of reptiles.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Threatened Amphibians',\n", + " 'description': '3 species of amphibians.',\n", + " 'type': 'Fauna'},\n", + " {'id': 'Threatened Fish',\n", + " 'description': '2 species of fish.',\n", + " 'type': 'Fauna'}],\n", + " 'rels': [{'start': 'Threatened Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Threatened Mammals'},\n", + " {'start': 'Threatened Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Threatened Birds'},\n", + " {'start': 'Threatened Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Threatened Reptiles'},\n", + " {'start': 'Threatened Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Threatened Amphibians'},\n", + " {'start': 'Threatened Species',\n", + " 'description': None,\n", + " 'type': 'INCLUDES',\n", + " 'end': 'Threatened Fish'}]},\n", + " {'communityId': '1-25',\n", + " 'nodes': [{'id': 'Maurya Empire',\n", + " 'description': 'Ancient empire based in the Ganges Basin.',\n", + " 'type': 'Empire'},\n", + " {'id': 'Gupta Empire',\n", + " 'description': 'Ancient empire based in the Ganges Basin.',\n", + " 'type': 'Empire'},\n", + " {'id': 'Ganges Basin', 'description': None, 'type': None}],\n", + " 'rels': [{'start': 'Ganges Basin',\n", + " 'description': None,\n", + " 'type': 'BASED_IN',\n", + " 'end': 'Maurya Empire'},\n", + " {'start': 'Ganges Basin',\n", + " 'description': None,\n", + " 'type': 'BASED_IN',\n", + " 'end': 'Gupta Empire'}]},\n", + " {'communityId': '1-26',\n", + " 'nodes': [{'id': 'Vijayanagara Empire',\n", + " 'description': 'Empire in south India that created a composite Hindu culture.',\n", + " 'type': 'Empire'},\n", + " {'id': 'South India', 'description': None, 'type': None}],\n", + " 'rels': [{'start': 'South India',\n", + " 'description': None,\n", + " 'type': 'BASED_IN',\n", + " 'end': 'Vijayanagara Empire'}]},\n", + " {'communityId': '1-27',\n", + " 'nodes': [{'id': 'Sikhism',\n", + " 'description': 'Religion that emerged in the Punjab, rejecting institutionalised religion.',\n", + " 'type': 'Religion'},\n", + " {'id': 'Punjab', 'description': None, 'type': None}],\n", + " 'rels': [{'start': 'Punjab',\n", + " 'description': None,\n", + " 'type': 'ORIGIN_OF',\n", + " 'end': 'Sikhism'}]},\n", + " {'communityId': '1-24',\n", + " 'nodes': [{'id': 'British East India Company',\n", + " 'description': 'Company that expanded rule in India, turning it into a colonial economy.',\n", + " 'type': 'Company'},\n", + " {'id': 'British Crown',\n", + " 'description': 'Began rule in India in 1858.',\n", + " 'type': 'Government'},\n", + " {'id': 'Indian Independence',\n", + " 'description': 'Event in 1947 when India was partitioned into two independent dominions.',\n", + " 'type': 'Event'}],\n", + " 'rels': [{'start': 'British East India Company',\n", + " 'description': None,\n", + " 'type': 'HISTORICAL_EVENT',\n", + " 'end': 'British Crown'},\n", + " {'start': 'British Crown',\n", + " 'description': None,\n", + " 'type': 'HISTORICAL_EVENT',\n", + " 'end': 'Indian Independence'}]}]" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "community_info" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "community_template = \"\"\"Based on the provided nodes and relationships that belong to the same graph community,\n", + "generate a natural language summary of the provided information:\n", + "{community_info}\n", + "\n", + "Summary:\"\"\" \n", + "model = \"openai-gpt-4o\"\n", + "llm, model_name = get_llm(model)\n", + "community_prompt = ChatPromptTemplate.from_messages(\n", + " [\n", + " (\n", + " \"system\",\n", + " \"Given an input triples, generate the information summary. No pre-amble.\",\n", + " ),\n", + " (\"human\", community_template),\n", + " ]\n", + ")\n", + "\n", + "community_chain = community_prompt | llm | StrOutputParser()" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "def prepare_string(data):\n", + " nodes_str = \"Nodes are:\\n\"\n", + " for node in data['nodes']:\n", + " node_id = node['id']\n", + " node_type = node['type']\n", + " if 'description' in node and node['description']:\n", + " node_description = f\", description: {node['description']}\"\n", + " else:\n", + " node_description = \"\"\n", + " nodes_str += f\"id: {node_id}, type: {node_type}{node_description}\\n\"\n", + "\n", + " rels_str = \"Relationships are:\\n\"\n", + " for rel in data['rels']:\n", + " start = rel['start']\n", + " end = rel['end']\n", + " rel_type = rel['type']\n", + " if 'description' in rel and rel['description']:\n", + " description = f\", description: {rel['description']}\"\n", + " else:\n", + " description = \"\"\n", + " rels_str += f\"({start})-[:{rel_type}]->({end}){description}\\n\"\n", + "\n", + " return nodes_str + \"\\n\" + rels_str\n", + "\n", + "def process_community(community):\n", + " stringify_info = prepare_string(community)\n", + " summary = community_chain.invoke({'community_info': stringify_info})\n", + " return {\"community\": community['communityId'], \"summary\": summary}" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Nodes are:\n", + "id: India, type: Country, description: Officially the Republic of India, located in South Asia.\n", + "id: Supreme Court Of India, type: Judiciary, description: Head of the independent judiciary.\n", + "id: Indian National Congress, type: Political party, description: Dominated Indian politics until 1977.\n", + "id: Sindhu, type: River, description: Name of the Indus River, from which the name India is derived.\n", + "id: Food And Agriculture Organization Of The United Nations, type: Organization, description: Estimates India's forest cover.\n", + "id: 2013 Forest Survey Of India, type: Report, description: States India's forest cover increased to 69.8 million hectares by 2012.\n", + "id: Yajnavalkya Smriti, type: Literature, description: Prohibited the cutting of trees.\n", + "id: Kautalyas Arthashastra, type: Literature, description: Discusses the need for forest administration.\n", + "id: Crown Land (Encroachment) Ordinance, type: Legislation, description: Promulgated in 1840 targeting forests in Britain's Asian colonies.\n", + "id: Indian Forest Act Of 1865, type: Legislation, description: Established the government's claims over forests.\n", + "id: Forest Act Of 1878, type: Legislation, description: Gave the British government control over all wastelands, including forests.\n", + "id: Sir Dietrich Brandis, type: Person, description: Inspector General of Forests in India from 1864 to 1883.\n", + "id: Indian Ocean, type: Ocean, description: Ocean bounded by India on the north.\n", + "id: Sri Lanka, type: Country, description: Country in the vicinity of India in the Indian Ocean.\n", + "id: Maldives, type: Country, description: Country in the vicinity of India in the Indian Ocean.\n", + "id: Myanmar, type: Country, description: Country sharing land border with India to the east.\n", + "id: Himalayan Mountain Range, type: Mountain range, description: Defines the northern frontiers of India.\n", + "id: China, type: Country, description: Country sharing land border with India to the north.\n", + "id: Bhutan, type: Country, description: Country sharing land border with India to the north.\n", + "id: Nepal, type: Country, description: Country sharing land border with India to the north.\n", + "id: Pakistan, type: Country, description: Country sharing land border with India to the west.\n", + "id: Bangladesh, type: Country, description: Country sharing land border with India to the east.\n", + "id: Ganges, type: River, description: The longest river originating in India.\n", + "id: Western Ghats, type: Biodiversity hotspot, description: One of the three biodiversity hotspots in India.\n", + "id: Eastern Himalayas, type: Biodiversity hotspot, description: One of the three biodiversity hotspots in India.\n", + "id: Indo-Burma Hotspot, type: Biodiversity hotspot, description: One of the three biodiversity hotspots in India.\n", + "id: Forests, type: Ecosystem, description: Covers about 24.6% of the total land area.\n", + "id: Indomalayan Realm, type: Realm, description: Geographical realm that includes India.\n", + "id: World, type: None\n", + "id: Public_Sector, type: None\n", + "id: Gdp, type: None\n", + "id: Economic_Liberalisation, type: None\n", + "id: Gdp_Growth, type: None\n", + "id: Consumer_Market, type: None\n", + "id: Wto, type: None\n", + "id: Ease_Of_Business_Index, type: None\n", + "id: Global_Competitiveness_Index, type: None\n", + "id: Billionaires, type: None\n", + "id: Welfare_State, type: None\n", + "id: Socialist_State, type: None\n", + "id: Social_Welfare_Spending, type: None\n", + "id: Labour_Force, type: None\n", + "id: Fdi, type: None\n", + "id: Free_Trade_Agreements, type: None\n", + "id: Service_Sector, type: None\n", + "id: Stock_Exchanges, type: None\n", + "id: Manufacturing, type: None\n", + "id: Population, type: None\n", + "id: Unemployment, type: None\n", + "id: Savings_Rate, type: None\n", + "id: Arabian Sea, type: Sea, description: Sea bounded by India on the northwest.\n", + "id: Bay Of Bengal, type: Bay, description: Bay bounded by India on the southeast.\n", + "id: Africa, type: Continent, description: Continent from which modern humans arrived on the Indian subcontinent.\n", + "id: Indus Valley Civilisation, type: Civilization, description: Civilisation that evolved from settled life in the western margins of the Indus river basin.\n", + "id: Sanskrit, type: Language, description: Indo-European language that diffused into India from the northwest.\n", + "id: Rigveda, type: Text, description: Ancient hymns recording the dawning of Hinduism in India.\n", + "id: Hinduism, type: Religion, description: Major religion in India, with roots in the Rigveda.\n", + "id: Buddhism, type: Religion, description: Religion that arose in India, proclaiming social orders unlinked to heredity.\n", + "id: Jainism, type: Religion, description: Religion that arose in India, proclaiming social orders unlinked to heredity.\n", + "id: Mughal Empire, type: Empire, description: Empire that began in 1526, known for its architecture and relative peace.\n", + "id: Indian Republic, type: Government, description: India has been a federal republic since 1950.\n", + "\n", + "Relationships are:\n", + "(India)-[:IS_PART_OF]->(Indomalayan Realm)\n", + "(India)-[:HAS]->(Public_Sector), description: About 1,900 public sector companies with complete control and ownership of railways, highways, and majority control in various industries.\n", + "(India)-[:HAS]->(Billionaires), description: One of the world's highest number of billionaires.\n", + "(India)-[:HAS]->(Labour_Force), description: World's second-largest labour force with 586 million workers.\n", + "(India)-[:HAS]->(Free_Trade_Agreements), description: Has free trade agreements with several nations and blocs.\n", + "(India)-[:HAS]->(Stock_Exchanges), description: Bombay Stock Exchange and National Stock Exchange are among the world's largest stock exchanges.\n", + "(India)-[:HAS]->(Population), description: Nearly 65% of India's population is rural.\n", + "(India)-[:RELATES_TO]->(Rigveda)\n", + "(India)-[:MEMBER_OF]->(Wto), description: Member of the World Trade Organization since 1 January 1995.\n", + "(India)-[:FACES]->(Unemployment), description: High unemployment and rising income inequality.\n", + "(India)-[:ADOPTED]->(Economic_Liberalisation), description: Adopted broad economic liberalisation in 1991.\n", + "(India)-[:CONSIDERED_AS]->(Welfare_State), description: Often considered a welfare state.\n", + "(India)-[:NEAR]->(Sri Lanka)\n", + "(India)-[:NEAR]->(Maldives)\n", + "(India)-[:BORDERS]->(Indian Ocean)\n", + "(India)-[:BORDERS]->(Myanmar)\n", + "(India)-[:BORDERS]->(Himalayan Mountain Range)\n", + "(India)-[:BORDERS]->(China)\n", + "(India)-[:BORDERS]->(Bhutan)\n", + "(India)-[:BORDERS]->(Nepal)\n", + "(India)-[:BORDERS]->(Pakistan)\n", + "(India)-[:BORDERS]->(Bangladesh)\n", + "(India)-[:BORDERS]->(Arabian Sea)\n", + "(India)-[:BORDERS]->(Bay Of Bengal)\n", + "(India)-[:SEPARATED_BY]->(Sri Lanka)\n", + "(India)-[:DERIVED_FROM]->(Sindhu)\n", + "(India)-[:ESTIMATES]->(Food And Agriculture Organization Of The United Nations), description: Estimates India's forest cover.\n", + "(India)-[:MAKES_UP]->(Service_Sector), description: Makes up more than 50% of GDP.\n", + "(India)-[:RANKS_AS]->(World), description: Fifth-largest economy by nominal GDP and third-largest by purchasing power parity (PPP).\n", + "(India)-[:RANKS_AS]->(Consumer_Market), description: Fourth-largest consumer market in the world.\n", + "(India)-[:RANKS_AS]->(Manufacturing), description: World's sixth-largest manufacturer, representing 2.6% of global manufacturing output.\n", + "(India)-[:DECLARED_AS]->(Socialist_State), description: Officially declared a socialist state as per the constitution.\n", + "(India)-[:ORIGIN_OF]->(Hinduism)\n", + "(India)-[:ORIGIN_OF]->(Buddhism)\n", + "(India)-[:ORIGIN_OF]->(Jainism)\n", + "(India)-[:GOVERNED_AS]->(Indian Republic)\n", + "(India)-[:RANKS]->(Gdp), description: 136th by GDP (nominal) and 125th by GDP (PPP) on a per capita income basis.\n", + "(India)-[:RANKS]->(Ease_Of_Business_Index), description: 63rd on the Ease of Doing Business index.\n", + "(India)-[:RANKS]->(Global_Competitiveness_Index), description: 40th on the Global Competitiveness Index.\n", + "(India)-[:SHARES_BORDERS_WITH]->(Myanmar)\n", + "(India)-[:SPENDING]->(Social_Welfare_Spending), description: Overall social welfare spending stood at 8.6% of GDP in 2021-22.\n", + "(India)-[:HISTORICAL_EVENT]->(Mughal Empire)\n", + "(India)-[:ORIGINATES_IN]->(Ganges)\n", + "(India)-[:HAS_BIODIVERSITY_HOTSPOT]->(Western Ghats)\n", + "(India)-[:HAS_BIODIVERSITY_HOTSPOT]->(Eastern Himalayas)\n", + "(India)-[:HAS_BIODIVERSITY_HOTSPOT]->(Indo-Burma Hotspot)\n", + "(India)-[:HAS_ECOSYSTEM]->(Forests)\n", + "(India)-[:AVERAGE_ANNUAL_GROWTH]->(Gdp_Growth), description: 6% to 7% since the start of the 21st century.\n", + "(India)-[:FOREIGN_DIRECT_INVESTMENT]->(Fdi), description: Foreign direct investment in 2021-22 was $82 billion.\n", + "(India)-[:GROSS_DOMESTIC_SAVINGS_RATE]->(Savings_Rate), description: Gross domestic savings rate stood at 29.3% of GDP in 2022.\n", + "(India)-[:HUMAN_ORIGIN]->(Africa)\n", + "(India)-[:HISTORICAL_DEVELOPMENT]->(Indus Valley Civilisation)\n", + "(India)-[:LANGUAGE_DIFFUSION]->(Sanskrit)\n", + "(Kautalyas Arthashastra)-[:DISCUSSES]->(India), description: Discusses the need for forest administration.\n", + "(Indian Forest Act Of 1865)-[:ESTABLISHES]->(India), description: Establishes government's claims over forests.\n", + "(Crown Land (Encroachment) Ordinance)-[:TARGETS]->(India), description: Targets forests in Britain's Asian colonies.\n", + "(Yajnavalkya Smriti)-[:PROHIBITS]->(India), description: Prohibits the cutting of trees.\n", + "(2013 Forest Survey Of India)-[:REPORTS_ON]->(India), description: Reports on forest cover increase.\n", + "(Supreme Court Of India)-[:PART_OF_JUDICIARY]->(India)\n", + "(Indian National Congress)-[:HISTORICALLY_DOMINANT_PARTY]->(India)\n", + "(Forest Act Of 1878)-[:GIVES_CONTROL]->(India), description: Gives control over all wastelands, including forests.\n", + "(Sir Dietrich Brandis)-[:INSPECTOR_GENERAL_OF]->(India), description: Inspector General of Forests in India from 1864 to 1883.\n", + "\n" + ] + } + ], + "source": [ + "print(prepare_string(community_info[0]))" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Processing communities: 0%| | 0/30 [00:00 pd.DataFrame:\n", + " \"\"\"Executes a Cypher statement and returns a DataFrame\"\"\"\n", + " return driver.execute_query(\n", + " cypher, parameters_=params, result_transformer_=Result.to_df\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "## Calculate before \n", + "db_query(\n", + " \"\"\"\n", + "MATCH (n:`__Community__`)<-[:IN_COMMUNITY]-()<-[:HAS_ENTITY]-(c)\n", + "WITH n, count(distinct c) AS chunkCount\n", + "SET n.weight = chunkCount\"\"\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## local and global search" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "index_name = \"entity_local\"\n", + "\n", + "# db_query(\n", + "# \"\"\"\n", + "# CREATE VECTOR INDEX \"\"\"\n", + "# + index_name\n", + "# + \"\"\" IF NOT EXISTS FOR (e:__Entity__) ON e.embedding\n", + "# OPTIONS {indexConfig: {\n", + "# `vector.dimensions`: 384,\n", + "# `vector.similarity_function`: 'cosine'\n", + "# }}\n", + "# \"\"\"\n", + "# )" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "topChunks = 3\n", + "topCommunities = 3\n", + "topOutsideRels = 10\n", + "topInsideRels = 10\n", + "topEntities = 10" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "lc_retrieval_query = \"\"\"\n", + "WITH collect(node) as nodes\n", + "// Entity - Text Unit Mapping\n", + "WITH\n", + "collect {\n", + " UNWIND nodes as n\n", + " MATCH (n)<-[:HAS_ENTITY]->(c:Chunk)\n", + " WITH c, count(distinct n) as freq\n", + " RETURN c.text AS chunkText\n", + " ORDER BY freq DESC\n", + " LIMIT $topChunks\n", + "} AS text_mapping,\n", + "// Entity - Report Mapping\n", + "collect {\n", + " UNWIND nodes as n\n", + " MATCH (n)-[:IN_COMMUNITY]->(c:__Community__)\n", + " WITH c, c.rank as rank, c.weight AS weight\n", + " RETURN c.summary \n", + " ORDER BY rank, weight DESC\n", + " LIMIT $topCommunities\n", + "} AS report_mapping,\n", + "// Outside Relationships \n", + "collect {\n", + " UNWIND nodes as n\n", + " MATCH (n)-[r:RELATED]-(m) \n", + " WHERE NOT m IN nodes\n", + " RETURN r.description AS descriptionText\n", + " ORDER BY r.rank, r.weight DESC \n", + " LIMIT $topOutsideRels\n", + "} as outsideRels,\n", + "// Inside Relationships \n", + "collect {\n", + " UNWIND nodes as n\n", + " MATCH (n)-[r:RELATED]-(m) \n", + " WHERE m IN nodes\n", + " RETURN r.description AS descriptionText\n", + " ORDER BY r.rank, r.weight DESC \n", + " LIMIT $topInsideRels\n", + "} as insideRels,\n", + "// Entities description\n", + "collect {\n", + " UNWIND nodes as n\n", + " RETURN n.description AS descriptionText\n", + "} as entities\n", + "// We don't have covariates or claims here\n", + "RETURN {Chunks: text_mapping, Reports: report_mapping, \n", + " Relationships: outsideRels + insideRels, \n", + " Entities: entities} AS text, 1.0 AS score, {} AS metadata\n", + "\"\"\"\n", + "\n", + "embeddings, dimension = load_embedding_model(\"sentence_transformer\")\n", + "lc_vector = Neo4jVector.from_existing_index(\n", + " embeddings,\n", + " url=os.environ[\"NEO4J_URI\"],\n", + " username=os.environ[\"NEO4J_USERNAME\"],\n", + " password=os.environ[\"NEO4J_PASSWORD\"],\n", + " index_name=index_name,\n", + " retrieval_query=lc_retrieval_query,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "docs = lc_vector.similarity_search_with_score(\n", + " \"Major cities of India\",\n", + " k=topEntities,\n", + " params={\n", + " \"topChunks\": topChunks,\n", + " \"topCommunities\": topCommunities,\n", + " \"topOutsideRels\": topOutsideRels,\n", + " \"topInsideRels\": topInsideRels,\n", + " },\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Entities:\n", + "- None\n", + "- None\n", + "- None\n", + "- One of the three biodiversity hotspots in India.\n", + "- Officially the Republic of India, located in South Asia.\n", + "- Geographical realm that includes India.\n", + "- One of the three biodiversity hotspots in India.\n", + "- Defines the northern frontiers of India.\n", + "- One of the three biodiversity hotspots in India.\n", + "- Commonly used name for the Republic of India.\n", + "Reports:\n", + "- India, officially the Republic of India, is a country located in South Asia and is part of the Indomalayan Realm. It shares borders with several countries including China, Bhutan, Nepal, Pakistan, Bangladesh, and Myanmar, and is bounded by the Indian Ocean, Arabian Sea, and Bay of Bengal. India is known for its rich biodiversity, featuring hotspots like the Western Ghats, Eastern Himalayas, and Indo-Burma Hotspot, and has a significant forest cover, which has been increasing as reported by the 2013 Forest Survey of India.\n", + "\n", + "India has a complex history, with ancient civilizations like the Indus Valley Civilisation and significant cultural contributions such as the Rigveda, which marks the dawn of Hinduism. It is also the birthplace of Buddhism and Jainism. The country has a diverse linguistic heritage, including the diffusion of the Indo-European language Sanskrit.\n", + "\n", + "Economically, India is a major global player, ranking as the fifth-largest economy by nominal GDP and third-largest by purchasing power parity (PPP). It has a significant public sector, a large labor force, and is a member of the World Trade Organization. The country has adopted broad economic liberalization since 1991, leading to substantial GDP growth and a robust service sector that makes up more than 50% of its GDP. India also has a high number of billionaires and is considered a welfare state with significant social welfare spending.\n", + "\n", + "Politically, India has been a federal republic since 1950, with the Indian National Congress historically dominating its politics until 1977. The Supreme Court of India heads its independent judiciary. The country has a rich legislative history concerning forest administration, with significant acts like the Indian Forest Act of 1865 and the Forest Act of 1878, and contributions from figures like Sir Dietrich Brandis, the Inspector General of Forests from 1864 to 1883.\n", + "\n", + "India's geographical and cultural landscape is further enriched by its rivers, such as the Ganges and Sindhu (Indus River), and its proximity to neighboring countries like Sri Lanka and the Maldives. The country is also part of the larger Indomalayan Realm and has historical ties to Africa, from where modern humans arrived on the Indian subcontinent.\n", + "- India, officially the Republic of India, is a country located in South Asia and is part of the Indomalayan Realm. It shares borders with several countries including China, Bhutan, Nepal, Pakistan, Bangladesh, and Myanmar, and is bounded by the Indian Ocean, Arabian Sea, and Bay of Bengal. India is known for its rich biodiversity, featuring hotspots like the Western Ghats, Eastern Himalayas, and Indo-Burma Hotspot, and has a significant forest cover, which has been increasing as reported by the 2013 Forest Survey of India.\n", + "\n", + "India has a complex history, with ancient civilizations like the Indus Valley Civilisation and significant cultural contributions such as the Rigveda, which marks the dawn of Hinduism. It is also the birthplace of Buddhism and Jainism. The country has a diverse linguistic heritage, including the diffusion of the Indo-European language Sanskrit.\n", + "\n", + "Economically, India is a major global player, ranking as the fifth-largest economy by nominal GDP and third-largest by purchasing power parity (PPP). It has a significant public sector, a large labor force, and is a member of the World Trade Organization. The country has adopted broad economic liberalization since 1991, leading to substantial GDP growth and a robust service sector that makes up more than 50% of its GDP. India also has a high number of billionaires and is considered a welfare state with significant social welfare spending.\n", + "\n", + "Politically, India has been a federal republic since 1950, with the Indian National Congress historically dominating its politics until 1977. The Supreme Court of India heads its independent judiciary. The country has a rich legislative history concerning forest administration, with significant acts like the Indian Forest Act of 1865 and the Forest Act of 1878, and contributions from figures like Sir Dietrich Brandis, the Inspector General of Forests from 1864 to 1883.\n", + "\n", + "India's geographical and cultural landscape is further enriched by its rivers, such as the Ganges and Sindhu (Indus River), and its proximity to neighboring countries like Sri Lanka and the Maldives. The country is also part of the larger Indomalayan Realm and has historical ties to Africa, from where modern humans arrived on the Indian subcontinent.\n", + "- India, officially the Republic of India, is a country located in South Asia and is part of the Indomalayan Realm. It shares borders with several countries including China, Bhutan, Nepal, Pakistan, Bangladesh, and Myanmar, and is bounded by the Indian Ocean, Arabian Sea, and Bay of Bengal. India is known for its rich biodiversity, featuring hotspots like the Western Ghats, Eastern Himalayas, and Indo-Burma Hotspot, and has a significant forest cover, which has been increasing as reported by the 2013 Forest Survey of India.\n", + "\n", + "India has a complex history, with ancient civilizations like the Indus Valley Civilisation and significant cultural contributions such as the Rigveda, which marks the dawn of Hinduism. It is also the birthplace of Buddhism and Jainism. The country has a diverse linguistic heritage, including the diffusion of the Indo-European language Sanskrit.\n", + "\n", + "Economically, India is a major global player, ranking as the fifth-largest economy by nominal GDP and third-largest by purchasing power parity (PPP). It has a significant public sector, a large labor force, and is a member of the World Trade Organization. The country has adopted broad economic liberalization since 1991, leading to substantial GDP growth and a robust service sector that makes up more than 50% of its GDP. India also has a high number of billionaires and is considered a welfare state with significant social welfare spending.\n", + "\n", + "Politically, India has been a federal republic since 1950, with the Indian National Congress historically dominating its politics until 1977. The Supreme Court of India heads its independent judiciary. The country has a rich legislative history concerning forest administration, with significant acts like the Indian Forest Act of 1865 and the Forest Act of 1878, and contributions from figures like Sir Dietrich Brandis, the Inspector General of Forests from 1864 to 1883.\n", + "\n", + "India's geographical and cultural landscape is further enriched by its rivers, such as the Ganges and Sindhu (Indus River), and its proximity to neighboring countries like Sri Lanka and the Maldives. The country is also part of the larger Indomalayan Realm and has historical ties to Africa, from where modern humans arrived on the Indian subcontinent.\n", + "Chunks:\n", + "- India is one of the most biodiverse regions and is home to a large variety of wildlife. It is one of the 17 megadiverse countries and includes three of the worlds 36 biodiversity hotspots – the Western Ghats, the Eastern Himalayas, and the Indo-Burma hotspot. About 24.6% of the total land area is covered by forests. It has various ecosystems ranging from the high altitude Himalayas, tropical evergreen forests along the Western Ghats, desert in the north-west, coastal plains and mangroves along the peninsular region. India lies within the Indomalayan realm and is home to about 7.6% of mammal, 14.7% of amphibian, 6% of bird, 6.2% of reptilian, and 6.2% of flowering plant species. Human encroachment, deforestation and poaching are significant challenges that threaten the existence of certain fauna and flora. Government of India established a system of national parks and\n", + "- threaten the existence of certain fauna and flora. Government of India established a system of national parks and protected areas in 1935, which have been subsequently expanded to nearly 1022 protected areas by 2023. India has enacted the Wildlife Protection Act of 1972 and special projects such as Project Tiger, Project Elephant and Project Dolphin for protection of critical species. == Fauna == India has an estimated 92,873 species of fauna, roughly about 7.5% of the species available worldwide. Insects form the major category with 63423 recorded species. India is home to 423 mammals, 1233 birds, 526 reptiles, 342 amphibians, 3022 fish apart from other species which form 7.6% of mammal, 14.7% of amphibian, 6% of bird, 6.2% of reptilian species worldwide. Many Indian species are descendants of species originating in Gondwana, of which India originally was a part. Peninsular Indias subsequent movement towards\n", + "- Gondwana, of which India originally was a part. Peninsular Indias subsequent movement towards, and collision with, the Laurasian landmass set off a mass exchange of species. However, volcanism in the Deccan Traps and climatic change 20 million years ago caused the extinction of many endemic Indian forms. Soon thereafter, mammals entered India from Asia through two zoogeographical passes on either side of the emerging Himalayas. As a result, among Indian species, only 12.6% of mammals and 4.5% of birds are endemic, contrasting with 45.8% of reptiles and 55.8% of amphibians India is home to several well-known large animals, including the Indian elephant, Indian rhinoceros, and Gaur. India is the only country where the big cats tiger and lion exist in the wild. Members of the cat family include Bengal tiger, Asiatic lion, Indian leopard, snow leopard, and clouded\n", + "Relationships:\n", + "\n" + ] + } + ], + "source": [ + "print(docs[0][0].page_content)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "model = \"openai-gpt-4o\"\n", + "llm, model_name = get_llm(model)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "MAP_SYSTEM_PROMPT = \"\"\"\n", + "---Role---\n", + "\n", + "You are a helpful assistant responding to questions about data in the tables provided.\n", + "\n", + "\n", + "---Goal---\n", + "\n", + "Generate a response consisting of a list of key points that responds to the user's question, summarizing all relevant information in the input data tables.\n", + "\n", + "You should use the data provided in the data tables below as the primary context for generating the response.\n", + "If you don't know the answer or if the input data tables do not contain sufficient information to provide an answer, just say so. Do not make anything up.\n", + "\n", + "Each key point in the response should have the following element:\n", + "- Description: A comprehensive description of the point.\n", + "- Importance Score: An integer score between 0-100 that indicates how important the point is in answering the user's question. An 'I don't know' type of response should have a score of 0.\n", + "\n", + "The response should be JSON formatted as follows:\n", + "{{\n", + " \"points\": [\n", + " {{\"description\": \"Description of point 1 [Data: Reports (report ids)]\", \"score\": score_value}},\n", + " {{\"description\": \"Description of point 2 [Data: Reports (report ids)]\", \"score\": score_value}}\n", + " ]\n", + "}}\n", + "\n", + "The response shall preserve the original meaning and use of modal verbs such as \"shall\", \"may\" or \"will\".\n", + "\n", + "Points supported by data should list the relevant reports as references as follows:\n", + "\"This is an example sentence supported by data references [Data: Reports (report ids)]\"\n", + "\n", + "**Do not list more than 5 record ids in a single reference**. Instead, list the top 5 most relevant record ids and add \"+more\" to indicate that there are more.\n", + "\n", + "For example:\n", + "\"Person X is the owner of Company Y and subject to many allegations of wrongdoing [Data: Reports (2, 7, 64, 46, 34, +more)]. He is also CEO of company X [Data: Reports (1, 3)]\"\n", + "\n", + "where 1, 2, 3, 7, 34, 46, and 64 represent the id (not the index) of the relevant data report in the provided tables.\n", + "\n", + "Do not include information where the supporting evidence for it is not provided.\n", + "\n", + "\n", + "---Data tables---\n", + "\n", + "{context_data}\n", + "\n", + "---Goal---\n", + "\n", + "Generate a response consisting of a list of key points that responds to the user's question, summarizing all relevant information in the input data tables.\n", + "\n", + "You should use the data provided in the data tables below as the primary context for generating the response.\n", + "If you don't know the answer or if the input data tables do not contain sufficient information to provide an answer, just say so. Do not make anything up.\n", + "\n", + "Each key point in the response should have the following element:\n", + "- Description: A comprehensive description of the point.\n", + "- Importance Score: An integer score between 0-100 that indicates how important the point is in answering the user's question. An 'I don't know' type of response should have a score of 0.\n", + "\n", + "The response shall preserve the original meaning and use of modal verbs such as \"shall\", \"may\" or \"will\".\n", + "\n", + "Points supported by data should list the relevant reports as references as follows:\n", + "\"This is an example sentence supported by data references [Data: Reports (report ids)]\"\n", + "\n", + "**Do not list more than 5 record ids in a single reference**. Instead, list the top 5 most relevant record ids and add \"+more\" to indicate that there are more.\n", + "\n", + "For example:\n", + "\"Person X is the owner of Company Y and subject to many allegations of wrongdoing [Data: Reports (2, 7, 64, 46, 34, +more)]. He is also CEO of company X [Data: Reports (1, 3)]\"\n", + "\n", + "where 1, 2, 3, 7, 34, 46, and 64 represent the id (not the index) of the relevant data report in the provided tables.\n", + "\n", + "Do not include information where the supporting evidence for it is not provided.\n", + "\n", + "The response should be JSON formatted as follows:\n", + "{{\n", + " \"points\": [\n", + " {{\"description\": \"Description of point 1 [Data: Reports (report ids)]\", \"score\": score_value}},\n", + " {{\"description\": \"Description of point 2 [Data: Reports (report ids)]\", \"score\": score_value}}\n", + " ]\n", + "}}\n", + "\"\"\"\n", + "\n", + "map_prompt = ChatPromptTemplate.from_messages(\n", + " [\n", + " (\n", + " \"system\",\n", + " MAP_SYSTEM_PROMPT,\n", + " ),\n", + " (\n", + " \"human\",\n", + " \"{question}\",\n", + " ),\n", + " ]\n", + ")\n", + "\n", + "map_chain = map_prompt | llm | StrOutputParser()" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "REDUCE_SYSTEM_PROMPT = \"\"\"\n", + "---Role---\n", + "\n", + "You are a helpful assistant responding to questions about a dataset by synthesizing perspectives from multiple analysts.\n", + "\n", + "\n", + "---Goal---\n", + "\n", + "Generate a response of the target length and format that responds to the user's question, summarize all the reports from multiple analysts who focused on different parts of the dataset.\n", + "\n", + "Note that the analysts' reports provided below are ranked in the **descending order of importance**.\n", + "\n", + "If you don't know the answer or if the provided reports do not contain sufficient information to provide an answer, just say so. Do not make anything up.\n", + "\n", + "The final response should remove all irrelevant information from the analysts' reports and merge the cleaned information into a comprehensive answer that provides explanations of all the key points and implications appropriate for the response length and format.\n", + "\n", + "Add sections and commentary to the response as appropriate for the length and format. Style the response in markdown.\n", + "\n", + "The response shall preserve the original meaning and use of modal verbs such as \"shall\", \"may\" or \"will\".\n", + "\n", + "The response should also preserve all the data references previously included in the analysts' reports, but do not mention the roles of multiple analysts in the analysis process.\n", + "\n", + "**Do not list more than 5 record ids in a single reference**. Instead, list the top 5 most relevant record ids and add \"+more\" to indicate that there are more.\n", + "\n", + "For example:\n", + "\n", + "\"Person X is the owner of Company Y and subject to many allegations of wrongdoing [Data: Reports (2, 7, 34, 46, 64, +more)]. He is also CEO of company X [Data: Reports (1, 3)]\"\n", + "\n", + "where 1, 2, 3, 7, 34, 46, and 64 represent the id (not the index) of the relevant data record.\n", + "\n", + "Do not include information where the supporting evidence for it is not provided.\n", + "\n", + "\n", + "---Target response length and format---\n", + "\n", + "{response_type}\n", + "\n", + "\n", + "---Analyst Reports---\n", + "\n", + "{report_data}\n", + "\n", + "\n", + "---Goal---\n", + "\n", + "Generate a response of the target length and format that responds to the user's question, summarize all the reports from multiple analysts who focused on different parts of the dataset.\n", + "\n", + "Note that the analysts' reports provided below are ranked in the **descending order of importance**.\n", + "\n", + "If you don't know the answer or if the provided reports do not contain sufficient information to provide an answer, just say so. Do not make anything up.\n", + "\n", + "The final response should remove all irrelevant information from the analysts' reports and merge the cleaned information into a comprehensive answer that provides explanations of all the key points and implications appropriate for the response length and format.\n", + "\n", + "The response shall preserve the original meaning and use of modal verbs such as \"shall\", \"may\" or \"will\".\n", + "\n", + "The response should also preserve all the data references previously included in the analysts' reports, but do not mention the roles of multiple analysts in the analysis process.\n", + "\n", + "**Do not list more than 5 record ids in a single reference**. Instead, list the top 5 most relevant record ids and add \"+more\" to indicate that there are more.\n", + "\n", + "For example:\n", + "\n", + "\"Person X is the owner of Company Y and subject to many allegations of wrongdoing [Data: Reports (2, 7, 34, 46, 64, +more)]. He is also CEO of company X [Data: Reports (1, 3)]\"\n", + "\n", + "where 1, 2, 3, 7, 34, 46, and 64 represent the id (not the index) of the relevant data record.\n", + "\n", + "Do not include information where the supporting evidence for it is not provided.\n", + "\n", + "\n", + "---Target response length and format---\n", + "\n", + "{response_type}\n", + "\n", + "Add sections and commentary to the response as appropriate for the length and format. Style the response in markdown.\n", + "\"\"\"\n", + "\n", + "reduce_prompt = ChatPromptTemplate.from_messages(\n", + " [\n", + " (\n", + " \"system\",\n", + " REDUCE_SYSTEM_PROMPT,\n", + " ),\n", + " (\n", + " \"human\",\n", + " \"{question}\",\n", + " ),\n", + " ]\n", + ")\n", + "reduce_chain = reduce_prompt | llm | StrOutputParser()" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "graph = Neo4jGraph(\n", + " url=os.environ[\"NEO4J_URI\"],\n", + " username=os.environ[\"NEO4J_USERNAME\"],\n", + " password=os.environ[\"NEO4J_PASSWORD\"],\n", + " refresh_schema=False,\n", + ")\n", + "\n", + "response_type: str = \"multiple paragraphs\"\n", + "\n", + "\n", + "def global_retriever(query: str, level: int, response_type: str = response_type) -> str:\n", + " community_data = graph.query(\n", + " \"\"\"\n", + " MATCH (c:__Community__)\n", + " WHERE c.level = $level\n", + " RETURN c.full_content AS output\n", + " \"\"\",\n", + " params={\"level\": level},\n", + " )\n", + " intermediate_results = []\n", + " for community in tqdm(community_data, desc=\"Processing communities\"):\n", + " intermediate_response = map_chain.invoke(\n", + " {\"question\": query, \"context_data\": community[\"output\"]}\n", + " )\n", + " intermediate_results.append(intermediate_response)\n", + " final_response = reduce_chain.invoke(\n", + " {\n", + " \"report_data\": intermediate_results,\n", + " \"question\": query,\n", + " \"response_type\": response_type,\n", + " }\n", + " )\n", + " return final_response" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING:neo4j.notifications:Received notification from DBMS server: {severity: WARNING} {code: Neo.ClientNotification.Statement.UnknownPropertyKeyWarning} {category: UNRECOGNIZED} {title: The provided property key is not in the database} {description: One of the property names in your query is not available in the database, make sure you didn't misspell it or that the label is available when you run this statement in your application (the missing property name is: full_content)} {position: line: 4, column: 14, offset: 69} for query: '\\n MATCH (c:__Community__)\\n WHERE c.level = $level\\n RETURN c.full_content AS output\\n '\n", + "Processing communities: 0it [00:00, ?it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "I'm sorry, but the provided reports do not contain sufficient information to provide an answer to your question about the major cities of India. If you have any other questions or need information on a different topic, please let me know!\n" + ] + } + ], + "source": [ + "print(global_retriever(\"Major cities of India?\", 2))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "chatbotenv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.13" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/frontend/src/App.css b/frontend/src/App.css index fe285c972..e912a05e2 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -121,7 +121,8 @@ height: 55px; object-fit: contain; } -.webImg{ + +.webImg { width: 80px; height: 80px; } @@ -240,9 +241,11 @@ .ndl-widget-content>div { overflow-wrap: break-word } -.word-break{ + +.word-break { word-break: break-word; } + .cellClass { width: 100%; height: 100%; @@ -345,22 +348,28 @@ margin-bottom: 0 !important; } -.node_label__value-container--has-value ,.relationship_label__value-container--has-value{ +.node_label__value-container--has-value, +.relationship_label__value-container--has-value { max-height: 215px; overflow-y: scroll !important; scrollbar-width: thin; } -.entity_extraction_Tab_node_label__value-container--has-value,.entity_extraction_Tab_relationship_label__value-container--has-value{ + +.entity_extraction_Tab_node_label__value-container--has-value, +.entity_extraction_Tab_relationship_label__value-container--has-value { max-height: 100px; overflow-y: scroll !important; scrollbar-width: thin; } -.tablet_entity_extraction_Tab_node_label__value-container--has-value,.tablet_entity_extraction_Tab_relationship_label__value-container--has-value{ + +.tablet_entity_extraction_Tab_node_label__value-container--has-value, +.tablet_entity_extraction_Tab_relationship_label__value-container--has-value { max-height: 80px; overflow-y: scroll !important; scrollbar-width: thin; } -.widthunset{ + +.widthunset { width: initial !important; height: initial !important; } @@ -372,4 +381,9 @@ .text-input-container.search-initiated { width: 60dvh; +} + +.custom-menu { + min-width: 250px; + max-width: 305px; } \ No newline at end of file diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index 3c6642665..53172256a 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -1,44 +1,37 @@ import { Box, Typography, - TextLink, Flex, Tabs, - LoadingSpinner, CypherCodeBlock, CypherCodeBlockProps, useCopyToClipboard, Banner, useMediaQuery, } from '@neo4j-ndl/react'; -import { DocumentDuplicateIconOutline, DocumentTextIconOutline } from '@neo4j-ndl/react/icons'; +import { DocumentDuplicateIconOutline, ClipboardDocumentCheckIconOutline } from '@neo4j-ndl/react/icons'; import '../../styling/info.css'; import Neo4jRetrievalLogo from '../../assets/images/Neo4jRetrievalLogo.png'; -import wikipedialogo from '../../assets/images/wikipedia.svg'; -import youtubelogo from '../../assets/images/youtube.svg'; -import gcslogo from '../../assets/images/gcs.webp'; -import s3logo from '../../assets/images/s3logo.png'; import { Chunk, + Community, Entity, ExtendedNode, ExtendedRelationship, - GroupedEntity, UserCredentials, chatInfoMessage, } from '../../types'; import { useContext, useEffect, useMemo, useState } from 'react'; -import HoverableLink from '../UI/HoverableLink'; import GraphViewButton from '../Graph/GraphViewButton'; import { chunkEntitiesAPI } from '../../services/ChunkEntitiesInfo'; import { useCredentials } from '../../context/UserCredentials'; -import { calcWordColor } from '@neo4j-devtools/word-color'; -import ReactMarkdown from 'react-markdown'; -import { GlobeAltIconOutline } from '@neo4j-ndl/react/icons'; -import { parseEntity, youtubeLinkValidation } from '../../utils/Utils'; import { ThemeWrapperContext } from '../../context/ThemeWrapper'; -import { ClipboardDocumentCheckIconOutline } from '@neo4j-ndl/react/icons'; import { tokens } from '@neo4j-ndl/base'; +import ChunkInfo from './ChunkInfo'; +import EntitiesInfo from './EntitiesInfo'; +import SourcesInfo from './SourcesInfo'; +import CommunitiesInfo from './Communities'; +import { chatModeLables } from '../../utils/Constants'; const ChatInfoModal: React.FC = ({ sources, @@ -53,8 +46,9 @@ const ChatInfoModal: React.FC = ({ }) => { const { breakpoints } = tokens; const isTablet = useMediaQuery(`(min-width:${breakpoints.xs}) and (max-width: ${breakpoints.lg})`); - const [activeTab, setActiveTab] = useState(error.length ? 10 : mode === 'graph' ? 4 : 3); + const [activeTab, setActiveTab] = useState(error?.length ? 10 : mode === chatModeLables.graph ? 4 : 3); const [infoEntities, setInfoEntities] = useState([]); + const [communities, setCommunities] = useState([]); const [loading, setLoading] = useState(false); const { userCredentials } = useCredentials(); const [nodes, setNodes] = useState([]); @@ -86,73 +80,79 @@ const ChatInfoModal: React.FC = ({ ], [copiedText, cypher_query] ); + useEffect(() => { - if (mode != 'graph' || error?.trim() !== '') { - setLoading(true); - chunkEntitiesAPI(userCredentials as UserCredentials, chunk_ids.map((c) => c.id).join(',')) - .then((response) => { - setInfoEntities(response.data.data.nodes); - setNodes(response.data.data.nodes); - setRelationships(response.data.data.relationships); - const chunks = response.data.data.chunk_data.map((chunk: any) => { - const chunkScore = chunk_ids.find((chunkdetail) => chunkdetail.id === chunk.id); - return { - ...chunk, - score: chunkScore?.score, - }; - }); - const sortedchunks = chunks.sort((a: any, b: any) => b.score - a.score); - setChunks(sortedchunks); + if (mode != chatModeLables.graph || error?.trim() !== '') { + (async () => { + setLoading(true); + try { + const response = await chunkEntitiesAPI( + userCredentials as UserCredentials, + chunk_ids.map((c) => c.id).join(','), + userCredentials?.database, + mode === chatModeLables.entity_vector + ); + if (response.data.status === 'Failure') { + throw new Error(response.data.error); + } + const nodesData = response?.data?.data?.nodes; + const relationshipsData = response?.data?.data?.relationships; + const communitiesData = response?.data?.data?.community_data; + const chunksData = response?.data?.data?.chunk_data; + + setInfoEntities( + nodesData.map((n: Entity) => { + if (!n.labels.length && mode === chatModeLables.entity_vector) { + return { + ...n, + labels: ['Entity'], + }; + } + return n; + }) + ); + setNodes( + nodesData.map((n: ExtendedNode) => { + if (!n.labels.length && mode === chatModeLables.entity_vector) { + return { + ...n, + labels: ['Entity'], + }; + } + return n ?? []; + }) + ); + setRelationships(relationshipsData ?? []); + setCommunities(communitiesData ?? []); + setChunks( + chunksData + .map((chunk: any) => { + const chunkScore = chunk_ids.find((chunkdetail) => chunkdetail.id === chunk.id); + return ( + { + ...chunk, + score: chunkScore?.score, + } ?? [] + ); + }) + .sort((a: any, b: any) => b.score - a.score) + ); setLoading(false); - }) - .catch((error) => { - console.error('Error fetching entities:', error); + } catch (error) { + console.error('Error fetching information:', error); setLoading(false); - }); + } + })(); } - () => { setcopiedText(false); }; }, [chunk_ids, mode, error]); - const groupedEntities = useMemo<{ [key: string]: GroupedEntity }>(() => { - return infoEntities.reduce((acc, entity) => { - const { label, text } = parseEntity(entity); - if (!acc[label]) { - const newColor = calcWordColor(label); - acc[label] = { texts: new Set(), color: newColor }; - } - acc[label].texts.add(text); - return acc; - }, {} as Record; color: string }>); - }, [infoEntities]); + const onChangeTabs = (tabId: number) => { setActiveTab(tabId); }; - const labelCounts = useMemo(() => { - const counts: { [label: string]: number } = {}; - for (let index = 0; index < infoEntities.length; index++) { - const entity = infoEntities[index]; - const { labels } = entity; - const [label] = labels; - counts[label] = counts[label] ? counts[label] + 1 : 1; - } - return counts; - }, [infoEntities]); - const sortedLabels = useMemo(() => { - return Object.keys(labelCounts).sort((a, b) => labelCounts[b] - labelCounts[a]); - }, [labelCounts]); - const generateYouTubeLink = (url: string, startTime: string) => { - try { - const urlObj = new URL(url); - urlObj.searchParams.set('t', startTime); - return urlObj.toString(); - } catch (error) { - console.error('Invalid URL:', error); - return ''; - } - }; return ( @@ -175,257 +175,38 @@ const ChatInfoModal: React.FC = ({ {error} ) : ( - {mode != 'graph' ? Sources used : <>} - {mode === 'graph+vector' || mode === 'graph' || mode === 'graph+vector+fulltext' ? ( + {mode != chatModeLables.graph ? Sources used : <>} + {mode != chatModeLables.graph ? Chunks : <>} + {mode === chatModeLables.graph_vector || + mode === chatModeLables.graph || + mode === chatModeLables.graph_vector_fulltext || + mode === chatModeLables.entity_vector ? ( Top Entities used ) : ( <> )} - {mode === 'graph' && cypher_query?.trim().length ? ( + {mode === chatModeLables.graph && cypher_query?.trim()?.length ? ( Generated Cypher Query ) : ( <> )} - {mode != 'graph' ? Chunks : <>} + {mode === chatModeLables.entity_vector? Communities : <>} )} - {sources.length ? ( -
      - {sources.map((link, index) => { - return ( -
    • - {link?.startsWith('http') || link?.startsWith('https') ? ( - <> - {link?.includes('wikipedia.org') && ( -
      - Wikipedia Logo - - - - {link} - - - -
      - )} - {link?.includes('storage.googleapis.com') && ( -
      - Google Cloud Storage Logo - - {decodeURIComponent(link).split('/').at(-1)?.split('?')[0] ?? 'GCS File'} - -
      - )} - {youtubeLinkValidation(link) && ( - <> -
      - - - - - {link} - - - -
      - - )} - {!link?.startsWith('s3://') && - !link?.includes('storage.googleapis.com') && - !link?.includes('wikipedia.org') && - !link?.includes('youtube.com') && ( -
      - - - {link} - -
      - )} - - ) : link?.startsWith('s3://') ? ( -
      - S3 Logo - - {decodeURIComponent(link).split('/').at(-1) ?? 'S3 File'} - -
      - ) : ( -
      - - - {link} - -
      - )} -
    • - ); - })} -
    - ) : ( - No Sources Found - )} +
    - {loading ? ( - - - - ) : Object.keys(groupedEntities).length > 0 || Object.keys(graphonly_entities).length > 0 ? ( -
      - {mode == 'graph' - ? graphonly_entities.map((label, index) => ( -
    • -
      - { - // @ts-ignore - label[Object.keys(label)[0]].id ?? Object.keys(label)[0] - } -
      -
    • - )) - : sortedLabels.map((label, index) => ( -
    • -
      - {label} ({labelCounts[label]}) -
      - - {Array.from(groupedEntities[label].texts).slice(0, 3).join(', ')} - -
    • - ))} -
    - ) : ( - No Entities Found - )} +
    - {loading ? ( - - - - ) : chunks.length > 0 ? ( -
    -
      - {chunks.map((chunk) => ( -
    • - {chunk?.page_number ? ( - <> -
      - - - {/* {chunk?.fileName}, Page: {chunk?.page_number} */} - {chunk?.fileName} - -
      - Similarity Score: {chunk?.score} - - ) : chunk?.url && chunk?.start_time ? ( - <> -
      - - - - {chunk?.fileName} - - -
      - Similarity Score: {chunk?.score} - - ) : chunk?.url && chunk?.url.includes('wikipedia.org') ? ( - <> -
      - - {chunk?.fileName} -
      - Similarity Score: {chunk?.score} - - ) : chunk?.url && chunk?.url.includes('storage.googleapis.com') ? ( - <> -
      - - {chunk?.fileName} -
      - Similarity Score: {chunk?.score} - - ) : chunk?.url && chunk?.url.startsWith('s3://') ? ( - <> -
      - - {chunk?.fileName} -
      - Similarity Score: {chunk?.score} - - ) : chunk?.url && - !chunk?.url.startsWith('s3://') && - !chunk?.url.includes('storage.googleapis.com') && - !chunk?.url.includes('wikipedia.org') && - !chunk?.url.includes('youtube.com') ? ( - <> -
      - - - {chunk?.url} - -
      - Similarity Score: {chunk?.score} - - ) : chunk.fileSource === 'local file' ? ( - <> - Similarity Score: {chunk?.score} - - ) : ( - <> - )} - {chunk?.text} -
    • - ))} -
    -
    - ) : ( - No Chunks Found - )} +
    = ({ className='min-h-40' /> + {mode === chatModeLables.entity_vector ? ( + + + + ) : ( + <> + )}
    - {activeTab == 4 && nodes.length && relationships.length ? ( + {activeTab == 4 && nodes?.length && relationships?.length ? ( diff --git a/frontend/src/components/ChatBot/ChatModeToggle.tsx b/frontend/src/components/ChatBot/ChatModeToggle.tsx index e82dfea4d..6c9bf459f 100644 --- a/frontend/src/components/ChatBot/ChatModeToggle.tsx +++ b/frontend/src/components/ChatBot/ChatModeToggle.tsx @@ -1,13 +1,14 @@ -import { StatusIndicator } from '@neo4j-ndl/react'; -import { useMemo } from 'react'; +import { StatusIndicator, Typography } from '@neo4j-ndl/react'; +import { useMemo, useEffect } from 'react'; import { useFileContext } from '../../context/UsersFiles'; import CustomMenu from '../UI/Menu'; -import { chatModes } from '../../utils/Constants'; +import { chatModeLables, chatModes } from '../../utils/Constants'; import { capitalize } from '@mui/material'; - +import { capitalizeWithPlus } from '../../utils/Utils'; +import { useCredentials } from '../../context/UserCredentials'; export default function ChatModeToggle({ menuAnchor, - closeHandler = () => {}, + closeHandler = () => { }, open, anchorPortal = true, disableBackdrop = false, @@ -18,7 +19,70 @@ export default function ChatModeToggle({ anchorPortal?: boolean; disableBackdrop?: boolean; }) { - const { setchatMode, chatMode } = useFileContext(); + const { setchatMode, chatMode, postProcessingTasks, selectedRows } = useFileContext(); + const isCommunityAllowed = postProcessingTasks.includes('create_communities'); + const { isGdsActive } = useCredentials(); + + useEffect(() => { + if (selectedRows.length !== 0) { + setchatMode(chatModeLables.graph_vector); + } else { + setchatMode(chatModeLables.graph_vector_fulltext); + } + }, [selectedRows]); + + const memoizedChatModes = useMemo(() => { + return isGdsActive && isCommunityAllowed + ? chatModes + : chatModes?.filter((m) => !m.mode.includes(chatModeLables.entity_vector)); + }, [isGdsActive, isCommunityAllowed]); + const menuItems = useMemo(() => { + return memoizedChatModes?.map((m) => { + const isDisabled = Boolean(selectedRows.length && !(m.mode === chatModeLables.vector || m.mode === chatModeLables.graph_vector)); + const handleModeChange = () => { + if (isDisabled) { + setchatMode(chatModeLables.graph_vector); + } else { + setchatMode(m.mode); + } + closeHandler(); + }; + return { + title: ( +
    + + {m.mode.includes('+') ? capitalizeWithPlus(m.mode) : capitalize(m.mode)} + +
    + {m.description} +
    +
    + ), + onClick: handleModeChange, + disabledCondition: isDisabled, + description: ( + + {chatMode === m.mode && ( + <> + {chatModeLables.selected} + + )} + {isDisabled && ( + <> + {chatModeLables.unavailableChatMode} + + )} + + ), + }; + }); + }, [chatMode, memoizedChatModes, setchatMode, closeHandler, selectedRows]); + + useEffect(() => { + if (!selectedRows.length && !chatMode) { + setchatMode(chatMode); + } + }, [setchatMode, selectedRows, chatMode]); return ( - chatModes?.map((m) => { - return { - title: m.includes('+') - ? m - .split('+') - .map((s) => capitalize(s)) - .join('+') - : capitalize(m), - onClick: () => { - setchatMode(m); - }, - disabledCondition: false, - description: ( - - {chatMode === m && ( - <> - Selected - - )} - - ), - }; - }), - [chatMode, chatModes] - )} - > + items={menuItems} + /> ); } diff --git a/frontend/src/components/ChatBot/Chatbot.tsx b/frontend/src/components/ChatBot/Chatbot.tsx index 7352b0ff4..412f485ed 100644 --- a/frontend/src/components/ChatBot/Chatbot.tsx +++ b/frontend/src/components/ChatBot/Chatbot.tsx @@ -14,8 +14,8 @@ import { v4 as uuidv4 } from 'uuid'; import { useFileContext } from '../../context/UsersFiles'; import clsx from 'clsx'; import ReactMarkdown from 'react-markdown'; -import IconButtonWithToolTip from '../UI/IconButtonToolTip'; -import { buttonCaptions, tooltips } from '../../utils/Constants'; +import { IconButtonWithToolTip } from '../UI/IconButtonToolTip'; +import { buttonCaptions, chatModeLables, tooltips } from '../../utils/Constants'; import useSpeechSynthesis from '../../hooks/useSpeech'; import ButtonWithToolTip from '../UI/ButtonWithToolTip'; import FallBackDialog from '../UI/FallBackDialog'; @@ -44,7 +44,7 @@ const Chatbot: FC = (props) => { const [tokensUsed, setTokensUsed] = useState(0); const [cypherQuery, setcypherQuery] = useState(''); const [copyMessageId, setCopyMessageId] = useState(null); - const [chatsMode, setChatsMode] = useState('graph+vector'); + const [chatsMode, setChatsMode] = useState(chatModeLables.graph_vector); const [graphEntitites, setgraphEntitites] = useState<[]>([]); const [messageError, setmessageError] = useState(''); @@ -89,6 +89,7 @@ const Chatbot: FC = (props) => { cypher_query?: string; graphonly_entities?: []; error?: string; + entitiysearchonly_entities?: chunk[]; }, index = 0 ) => { @@ -119,6 +120,7 @@ const Chatbot: FC = (props) => { cypher_query: response?.cypher_query, graphonly_entities: response?.graphonly_entities, error: response.error, + entitiysearchonly_entities: response.entitiysearchonly_entities, }, ]); } else { @@ -141,6 +143,7 @@ const Chatbot: FC = (props) => { lastmsg.cypher_query = response.cypher_query; lastmsg.graphonly_entities = response.graphonly_entities; lastmsg.error = response.error; + lastmsg.entities = response.entitiysearchonly_entities; return msgs.map((msg, index) => { if (index === msgs.length - 1) { return lastmsg; @@ -174,6 +177,7 @@ const Chatbot: FC = (props) => { let cypher_query; let graphonly_entities; let error; + let entitiysearchonly_entities; const datetime = `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`; const userMessage = { id: Date.now(), user: 'user', message: inputMessage, datetime: datetime }; setListMessages([...listMessages, userMessage]); @@ -198,6 +202,7 @@ const Chatbot: FC = (props) => { chatingMode = chatresponse?.data?.data?.info?.mode; cypher_query = chatresponse?.data?.data?.info?.cypher_query ?? ''; graphonly_entities = chatresponse?.data.data.info.context ?? []; + entitiysearchonly_entities = chatresponse?.data.data.info.entities; error = chatresponse.data.data.info.error ?? ''; const finalbotReply = { reply: chatbotReply, @@ -212,6 +217,7 @@ const Chatbot: FC = (props) => { cypher_query, graphonly_entities, error, + entitiysearchonly_entities, }; simulateTypingEffect(finalbotReply); } catch (error) { @@ -349,7 +355,9 @@ const Chatbot: FC = (props) => { setModelModal(chat.model ?? ''); setSourcesModal(chat.sources ?? []); setResponseTime(chat.response_time ?? 0); - setChunkModal(chat.chunk_ids ?? []); + setChunkModal( + chat.mode === 'entity search+vector' ? chat.entities ?? [] : chat.chunk_ids ?? [] + ); setTokensUsed(chat.total_tokens ?? 0); setcypherQuery(chat.cypher_query ?? ''); setShowInfoModal(true); diff --git a/frontend/src/components/ChatBot/ChunkInfo.tsx b/frontend/src/components/ChatBot/ChunkInfo.tsx new file mode 100644 index 000000000..350b41b98 --- /dev/null +++ b/frontend/src/components/ChatBot/ChunkInfo.tsx @@ -0,0 +1,125 @@ +import { FC, useContext } from 'react'; +import { ChunkProps } from '../../types'; +import { Box, LoadingSpinner, TextLink, Typography } from '@neo4j-ndl/react'; +import { DocumentTextIconOutline, GlobeAltIconOutline } from '@neo4j-ndl/react/icons'; +import wikipedialogo from '../../assets/images/wikipedia.svg'; +import youtubelogo from '../../assets/images/youtube.svg'; +import gcslogo from '../../assets/images/gcs.webp'; +import s3logo from '../../assets/images/s3logo.png'; +import ReactMarkdown from 'react-markdown'; +import { generateYouTubeLink, getLogo, isAllowedHost } from '../../utils/Utils'; +import { ThemeWrapperContext } from '../../context/ThemeWrapper'; + +const ChunkInfo: FC = ({ loading, chunks }) => { + const themeUtils = useContext(ThemeWrapperContext); + + return ( + <> + {loading ? ( + + + + ) : chunks?.length > 0 ? ( +
    +
      + {chunks.map((chunk) => ( +
    • + {chunk?.page_number ? ( + <> +
      + + + {chunk?.fileName} + +
      + Similarity Score: {chunk?.score} + + ) : chunk?.url && chunk?.start_time ? ( + <> +
      + + + + {chunk?.fileName} + + +
      + Similarity Score: {chunk?.score} + + ) : chunk?.url && new URL(chunk.url).host === 'wikipedia.org' ? ( + <> +
      + + {chunk?.fileName} +
      + Similarity Score: {chunk?.score} + + ) : chunk?.url && new URL(chunk.url).host === 'storage.googleapis.com' ? ( + <> +
      + + {chunk?.fileName} +
      + Similarity Score: {chunk?.score} + + ) : chunk?.url && chunk?.url.startsWith('s3://') ? ( + <> +
      + + {chunk?.fileName} +
      + Similarity Score: {chunk?.score} + + ) : chunk?.url && + !chunk?.url.startsWith('s3://') && + !isAllowedHost(chunk?.url, ['storage.googleapis.com', 'wikipedia.org', 'youtube.com']) ? ( + <> +
      + + + {chunk?.url} + +
      + Similarity Score: {chunk?.score} + + ) : ( + <> +
      + {chunk.fileSource === 'local file' ? ( + + ) : ( + + )} + + {chunk.fileName} + +
      + + )} + {chunk?.text} +
    • + ))} +
    +
    + ) : ( + No Chunks Found + )} + + ); +}; + +export default ChunkInfo; diff --git a/frontend/src/components/ChatBot/Communities.tsx b/frontend/src/components/ChatBot/Communities.tsx new file mode 100644 index 000000000..9b530fd0f --- /dev/null +++ b/frontend/src/components/ChatBot/Communities.tsx @@ -0,0 +1,36 @@ +import { Box, LoadingSpinner, Flex, Typography } from '@neo4j-ndl/react'; +import { FC } from 'react'; +import ReactMarkdown from 'react-markdown'; +import { CommunitiesProps } from '../../types'; + +const CommunitiesInfo: FC = ({ loading, communities }) => { + return ( + <> + {loading ? ( + + + + ) : communities?.length > 0 ? ( +
    +
      + {communities.map((community, index) => ( +
    • +
      + + ID : + {community.id} + + {community.summary} +
      +
    • + ))} +
    +
    + ) : ( + No Communities Found + )} + + ); +}; + +export default CommunitiesInfo; diff --git a/frontend/src/components/ChatBot/EntitiesInfo.tsx b/frontend/src/components/ChatBot/EntitiesInfo.tsx new file mode 100644 index 000000000..6c6e0784e --- /dev/null +++ b/frontend/src/components/ChatBot/EntitiesInfo.tsx @@ -0,0 +1,91 @@ +import { Box, GraphLabel, LoadingSpinner, Typography } from '@neo4j-ndl/react'; +import { FC, useMemo } from 'react'; +import { EntitiesProps, GroupedEntity } from '../../types'; +import { calcWordColor } from '@neo4j-devtools/word-color'; +import { graphLabels } from '../../utils/Constants'; +import { parseEntity } from '../../utils/Utils'; + +const EntitiesInfo: FC = ({ loading, mode, graphonly_entities, infoEntities }) => { + const groupedEntities = useMemo<{ [key: string]: GroupedEntity }>(() => { + const items = infoEntities.reduce((acc, entity) => { + const { label, text } = parseEntity(entity); + if (!acc[label]) { + const newColor = calcWordColor(label); + acc[label] = { texts: new Set(), color: newColor }; + } + acc[label].texts.add(text); + return acc; + }, {} as Record; color: string }>); + return items; + }, [infoEntities]); + + const labelCounts = useMemo(() => { + const counts: { [label: string]: number } = {}; + for (let index = 0; index < infoEntities?.length; index++) { + const entity = infoEntities[index]; + const { labels } = entity; + const [label] = labels; + counts[label] = counts[label] ? counts[label] + 1 : 1; + } + return counts; + }, [infoEntities]); + + const sortedLabels = useMemo(() => { + return Object.keys(labelCounts).sort((a, b) => labelCounts[b] - labelCounts[a]); + }, [labelCounts]); + return ( + <> + {loading ? ( + + + + ) : Object.keys(groupedEntities)?.length > 0 || Object.keys(graphonly_entities)?.length > 0 ? ( +
      + {mode == 'graph' + ? graphonly_entities.map((label, index) => ( +
    • +
      + { + // @ts-ignore + label[Object.keys(label)[0]].id ?? Object.keys(label)[0] + } +
      +
    • + )) + : sortedLabels.map((label, index) => { + const entity = groupedEntities[label == 'undefined' ? 'Entity' : label]; + return ( +
    • + e.preventDefault()} + > + {label === '__Community__' ? graphLabels.community : label} ({labelCounts[label]}) + + + {Array.from(entity.texts).slice(0, 3).join(', ')} + +
    • + ); + })} +
    + ) : ( + No Entities Found + )} + + ); +}; + +export default EntitiesInfo; diff --git a/frontend/src/components/ChatBot/ExpandedChatButtonContainer.tsx b/frontend/src/components/ChatBot/ExpandedChatButtonContainer.tsx index 49925466f..465687c4b 100644 --- a/frontend/src/components/ChatBot/ExpandedChatButtonContainer.tsx +++ b/frontend/src/components/ChatBot/ExpandedChatButtonContainer.tsx @@ -2,7 +2,7 @@ import { TrashIconOutline, XMarkIconOutline } from '@neo4j-ndl/react/icons'; import ChatModeToggle from './ChatModeToggle'; import { Box, IconButton } from '@neo4j-ndl/react'; import { IconProps } from '../../types'; -import IconButtonWithToolTip from '../UI/IconButtonToolTip'; +import { IconButtonWithToolTip } from '../UI/IconButtonToolTip'; import { tooltips } from '../../utils/Constants'; import { useState } from 'react'; import { RiChatSettingsLine } from 'react-icons/ri'; diff --git a/frontend/src/components/ChatBot/Info/InfoModal.tsx b/frontend/src/components/ChatBot/Info/InfoModal.tsx deleted file mode 100644 index 3a6ef37bb..000000000 --- a/frontend/src/components/ChatBot/Info/InfoModal.tsx +++ /dev/null @@ -1,361 +0,0 @@ -import { Box, Typography, TextLink, Flex, Tabs, LoadingSpinner } from '@neo4j-ndl/react'; -import { DocumentTextIconOutline } from '@neo4j-ndl/react/icons'; -import '../../../styling/info.css'; -import Neo4jRetrievalLogo from '../../../assets/images/Neo4jRetrievalLogo.png'; -import wikipedialogo from '../../../assets/images/Wikipedia-logo-v2.svg'; -import youtubelogo from '../../../assets/images/youtube.png'; -import gcslogo from '../../../assets/images/gcs.webp'; -import s3logo from '../../../assets/images/s3logo.png'; - -import { - Chunk, - Entity, - ExtendedNode, - ExtendedRelationship, - GroupedEntity, - UserCredentials, - chatInfoMessage, -} from '../../../types'; -import { useEffect, useMemo, useState } from 'react'; -import HoverableLink from '../../UI/HoverableLink'; -import GraphViewButton from '../../Graph/GraphViewButton'; -import { chunkEntitiesAPI } from '../../../services/ChunkEntitiesInfo'; -import { useCredentials } from '../../../context/UserCredentials'; -import { calcWordColor } from '@neo4j-devtools/word-color'; -import ReactMarkdown from 'react-markdown'; -import { GlobeAltIconOutline } from '@neo4j-ndl/react/icons'; -import { youtubeLinkValidation } from '../../../utils/Utils'; -const InfoModal: React.FC = ({ sources, model, total_tokens, response_time, chunk_ids }) => { - const [activeTab, setActiveTab] = useState(3); - const [infoEntities, setInfoEntities] = useState([]); - const [loading, setLoading] = useState(false); - const { userCredentials } = useCredentials(); - const [nodes, setNodes] = useState([]); - const [relationships, setRelationships] = useState([]); - const [chunks, setChunks] = useState([]); - const parseEntity = (entity: Entity) => { - const { labels, properties } = entity; - const [label] = labels; - const text = properties.id; - return { label, text }; - }; - useEffect(() => { - setLoading(true); - chunkEntitiesAPI(userCredentials as UserCredentials, chunk_ids.map((c) => c.id).join(',')) - .then((response) => { - setInfoEntities(response.data.data.nodes); - setNodes(response.data.data.nodes); - setRelationships(response.data.data.relationships); - const chunks = response.data.data.chunk_data.map((chunk: any) => { - const chunkScore = chunk_ids.find((chunkdetail) => chunkdetail.id === chunk.id); - return { - ...chunk, - score: chunkScore?.score, - }; - }); - const sortedchunks = chunks.sort((a: any, b: any) => b.score - a.score); - setChunks(sortedchunks); - setLoading(false); - }) - .catch((error) => { - console.error('Error fetching entities:', error); - setLoading(false); - }); - }, [chunk_ids]); - const groupedEntities = useMemo<{ [key: string]: GroupedEntity }>(() => { - return infoEntities.reduce((acc, entity) => { - const { label, text } = parseEntity(entity); - if (!acc[label]) { - const newColor = calcWordColor(label); - acc[label] = { texts: new Set(), color: newColor }; - } - acc[label].texts.add(text); - return acc; - }, {} as Record; color: string }>); - }, [infoEntities]); - const onChangeTabs = (tabId: number) => { - setActiveTab(tabId); - }; - const labelCounts = useMemo(() => { - const counts: { [label: string]: number } = {}; - for (let index = 0; index < infoEntities.length; index++) { - const entity = infoEntities[index]; - const { labels } = entity; - const [label] = labels; - counts[label] = counts[label] ? counts[label] + 1 : 1; - } - return counts; - }, [infoEntities]); - const sortedLabels = useMemo(() => { - return Object.keys(labelCounts).sort((a, b) => labelCounts[b] - labelCounts[a]); - }, [labelCounts]); - - const generateYouTubeLink = (url: string, startTime: string) => { - try { - const urlObj = new URL(url); - urlObj.searchParams.set('t', startTime); - return urlObj.toString(); - } catch (error) { - console.error('Invalid URL:', error); - return ''; - } - }; - return ( - - - - - Retrieval information - - To generate this response, in {response_time} seconds we used{' '} - {total_tokens} tokens with the model{' '} - {model}. - - - - - Sources used - Top Entities used - Chunks - - - - {sources.length ? ( -
      - {sources.map((link, index) => { - return ( -
    • - {link?.startsWith('http') || link?.startsWith('https') ? ( - <> - {link?.includes('wikipedia.org') && ( -
      - Wikipedia Logo - - - - {link} - - - -
      - )} - {link?.includes('storage.googleapis.com') && ( -
      - Google Cloud Storage Logo - - {decodeURIComponent(link).split('/').at(-1)?.split('?')[0] ?? 'GCS File'} - -
      - )} - {link?.startsWith('s3://') && ( -
      - S3 Logo - - {decodeURIComponent(link).split('/').at(-1) ?? 'S3 File'} - -
      - )} - {youtubeLinkValidation(link) && ( - <> -
      - - - - - {link} - - - -
      - - )} - {!link?.startsWith('s3://') && - !link?.includes('storage.googleapis.com') && - !link?.includes('wikipedia.org') && - !link?.includes('youtube.com') && ( -
      - - - {link} - -
      - )} - - ) : ( -
      - - - {link} - - {/* {chunks?.length > 0 && ( - - - Page{' '} - {chunks - .map((c) => c.page_number as number) - .sort((a, b) => a - b) - .join(', ')} - - )} */} -
      - )} -
    • - ); - })} -
    - ) : ( - No Sources Found - )} -
    - - {loading ? ( - - - - ) : Object.keys(groupedEntities).length > 0 ? ( -
      - {sortedLabels.map((label, index) => ( -
    • -
      - {label} ({labelCounts[label]}) -
      - - {Array.from(groupedEntities[label].texts).slice(0, 3).join(', ')} - -
    • - ))} -
    - ) : ( - No Entities Found - )} -
    - - {loading ? ( - - - - ) : chunks.length > 0 ? ( -
    -
      - {chunks.map((chunk) => ( -
    • - {chunk?.page_number ? ( - <> -
      - - - {/* {chunk?.fileName}, Page: {chunk?.page_number} */} - {chunk?.fileName} - -
      - Similarity Score: {chunk?.score} - - ) : chunk?.url && chunk?.start_time ? ( - <> -
      - - - - {chunk?.fileName} - - -
      - Similarity Score: {chunk?.score} - - ) : chunk?.url && chunk?.url.includes('wikipedia.org') ? ( - <> -
      - - {chunk?.fileName} -
      - Similarity Score: {chunk?.score} - - ) : chunk?.url && chunk?.url.includes('storage.googleapis.com') ? ( - <> -
      - - {chunk?.fileName} -
      - Similarity Score: {chunk?.score} - - ) : chunk?.url && chunk?.url.startsWith('s3://') ? ( - <> -
      - - {chunk?.fileName} -
      - - ) : chunk?.url && - !chunk?.url.startsWith('s3://') && - !chunk?.url.includes('storage.googleapis.com') && - !chunk?.url.includes('wikipedia.org') && - !chunk?.url.includes('youtube.com') ? ( - <> -
      - - - {chunk?.url} - -
      - Similarity Score: {chunk?.score} - - ) : ( - <> - )} - {chunk?.text} -
    • - ))} -
    -
    - ) : ( - No Chunks Found - )} -
    -
    - {activeTab == 4 && nodes.length && relationships.length ? ( - - - - ) : ( - <> - )} -
    - ); -}; -export default InfoModal; diff --git a/frontend/src/components/ChatBot/SourcesInfo.tsx b/frontend/src/components/ChatBot/SourcesInfo.tsx new file mode 100644 index 000000000..91fee511f --- /dev/null +++ b/frontend/src/components/ChatBot/SourcesInfo.tsx @@ -0,0 +1,137 @@ +import { FC, useContext } from 'react'; +import { SourcesProps } from '../../types'; +import { Box, LoadingSpinner, TextLink, Typography } from '@neo4j-ndl/react'; +import { DocumentTextIconOutline, GlobeAltIconOutline } from '@neo4j-ndl/react/icons'; +import { getLogo, isAllowedHost, youtubeLinkValidation } from '../../utils/Utils'; +import { ThemeWrapperContext } from '../../context/ThemeWrapper'; +import HoverableLink from '../UI/HoverableLink'; +import wikipedialogo from '../../assets/images/wikipedia.svg'; +import youtubelogo from '../../assets/images/youtube.svg'; +import gcslogo from '../../assets/images/gcs.webp'; +import s3logo from '../../assets/images/s3logo.png'; + +const SourcesInfo: FC = ({ loading, mode, chunks, sources }) => { + const themeUtils = useContext(ThemeWrapperContext); + return ( + <> + {loading ? ( + + + + ) : mode === 'entity search+vector' && chunks?.length ? ( +
      + {chunks + .map((c) => ({ fileName: c.fileName, fileSource: c.fileSource })) + .map((s, index) => { + return ( +
    • +
      + {s.fileSource === 'local file' ? ( + + ) : ( + + )} + + {s.fileName} + +
      +
    • + ); + })} +
    + ) : sources?.length ? ( +
      + {sources.map((link, index) => { + return ( +
    • + {link?.startsWith('http') || link?.startsWith('https') ? ( + <> + {isAllowedHost(link, ['wikipedia.org']) && ( +
      + Wikipedia Logo + + + + {link} + + + +
      + )} + {isAllowedHost(link, ['storage.googleapis.com']) && ( +
      + Google Cloud Storage Logo + + {decodeURIComponent(link).split('/').at(-1)?.split('?')[0] ?? 'GCS File'} + +
      + )} + {youtubeLinkValidation(link) && ( + <> +
      + + + + + {link} + + + +
      + + )} + {!link?.startsWith('s3://') && + !isAllowedHost(link, ['storage.googleapis.com', 'wikipedia.org', 'youtube.com']) && ( +
      + + + {link} + +
      + )} + + ) : link?.startsWith('s3://') ? ( +
      + S3 Logo + + {decodeURIComponent(link).split('/').at(-1) ?? 'S3 File'} + +
      + ) : ( +
      + + + {link} + +
      + )} +
    • + ); + })} +
    + ) : ( + No Sources Found + )} + + ); +}; + +export default SourcesInfo; diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 8bbe10f92..517ada241 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -28,10 +28,11 @@ import FallBackDialog from './UI/FallBackDialog'; import DeletePopUp from './Popups/DeletePopUp/DeletePopUp'; import GraphEnhancementDialog from './Popups/GraphEnhancementDialog'; import { tokens } from '@neo4j-ndl/base'; +import axios from 'axios'; +import DatabaseStatusIcon from './UI/DatabaseStatusIcon'; import RetryConfirmationDialog from './Popups/RetryConfirmation/Index'; import retry from '../services/retry'; import { showErrorToast, showNormalToast, showSuccessToast } from '../utils/toasts'; -import axios from 'axios'; const ConnectionModal = lazy(() => import('./Popups/ConnectionModal/ConnectionModal')); const ConfirmationDialog = lazy(() => import('./Popups/LargeFilePopUp/ConfirmationDialog')); @@ -58,7 +59,8 @@ const Content: React.FC = ({ }); const [openGraphView, setOpenGraphView] = useState(false); const [inspectedName, setInspectedName] = useState(''); - const { setUserCredentials, userCredentials, connectionStatus, setConnectionStatus } = useCredentials(); + const { setUserCredentials, userCredentials, connectionStatus, setConnectionStatus, isGdsActive, setGdsActive } = + useCredentials(); const [showConfirmationModal, setshowConfirmationModal] = useState(false); const [extractLoading, setextractLoading] = useState(false); const [retryFile, setRetryFile] = useState(''); @@ -109,10 +111,13 @@ const Content: React.FC = ({ setUserCredentials({ uri: neo4jConnection.uri, userName: neo4jConnection.user, - password: neo4jConnection.password, + password: atob(neo4jConnection.password), database: neo4jConnection.database, port: neo4jConnection.uri.split(':')[2], }); + if (neo4jConnection.isgdsActive !== undefined) { + setGdsActive(neo4jConnection.isgdsActive); + } } else { setOpenConnection((prev) => ({ ...prev, openPopUp: true })); } @@ -140,7 +145,12 @@ const Content: React.FC = ({ if (processedCount == batchSize) { handleGenerateGraph([], true); } - }, [processedCount, userCredentials]); + if (processedCount === 1 && queue.isEmpty()) { + (async () => { + await postProcessing(userCredentials as UserCredentials, postProcessingTasks); + })(); + } + }, [processedCount, userCredentials, queue]); useEffect(() => { if (afterFirstRender) { @@ -162,13 +172,19 @@ const Content: React.FC = ({ (async () => { const parsedData = JSON.parse(connection); console.log(parsedData.uri); - const response = await connectAPI(parsedData.uri, parsedData.user, parsedData.password, parsedData.database); + const response = await connectAPI( + parsedData.uri, + parsedData.user, + atob(parsedData.password), + parsedData.database + ); if (response?.data?.status === 'Success') { localStorage.setItem( 'neo4j.connection', JSON.stringify({ ...parsedData, userDbVectorIndex: response.data.data.db_vector_dimension, + password: btoa(atob(parsedData.password)), }) ); if ( @@ -356,7 +372,10 @@ const Content: React.FC = ({ return data; }; - const addFilesToQueue = (remainingFiles: CustomFile[]) => { + const addFilesToQueue = async (remainingFiles: CustomFile[]) => { + if (!remainingFiles.length) { + await postProcessing(userCredentials as UserCredentials, postProcessingTasks); + } for (let index = 0; index < remainingFiles.length; index++) { const f = remainingFiles[index]; setFilesData((prev) => @@ -434,13 +453,11 @@ const Content: React.FC = ({ } Promise.allSettled(data).then(async (_) => { setextractLoading(false); - await postProcessing(userCredentials as UserCredentials, postProcessingTasks); }); } else if (queueFiles && !queue.isEmpty() && processingFilesCount < batchSize) { data = scheduleBatchWiseProcess(queue.items, true); Promise.allSettled(data).then(async (_) => { setextractLoading(false); - await postProcessing(userCredentials as UserCredentials, postProcessingTasks); }); } else { addFilesToQueue(filesTobeProcessed as CustomFile[]); @@ -460,7 +477,6 @@ const Content: React.FC = ({ } Promise.allSettled(data).then(async (_) => { setextractLoading(false); - await postProcessing(userCredentials as UserCredentials, postProcessingTasks); }); } else { const selectedNewFiles = childRef.current @@ -739,16 +755,14 @@ const Content: React.FC = ({ chunksExistsWithDifferentEmbedding={openConnection.chunksExistsWithDifferentDimension} /> -
    Neo4j connection - {!connectionStatus ? : } - {connectionStatus ? ( - {userCredentials?.uri} - ) : ( - Not Connected - )} +
    {!isSchema ? ( diff --git a/frontend/src/components/DataSources/Local/DropZone.tsx b/frontend/src/components/DataSources/Local/DropZone.tsx index 7ff5d90d2..0278e679e 100644 --- a/frontend/src/components/DataSources/Local/DropZone.tsx +++ b/frontend/src/components/DataSources/Local/DropZone.tsx @@ -7,7 +7,7 @@ import { useFileContext } from '../../../context/UsersFiles'; import { CustomFile, CustomFileBase, UserCredentials } from '../../../types'; import { buttonCaptions, chunkSize } from '../../../utils/Constants'; import { InformationCircleIconOutline } from '@neo4j-ndl/react/icons'; -import IconButtonWithToolTip from '../../UI/IconButtonToolTip'; +import { IconButtonWithToolTip } from '../../UI/IconButtonToolTip'; import { uploadAPI } from '../../../utils/FileAPI'; import { showErrorToast, showSuccessToast } from '../../../utils/toasts'; diff --git a/frontend/src/components/DataSources/Local/DropZoneForSmallLayouts.tsx b/frontend/src/components/DataSources/Local/DropZoneForSmallLayouts.tsx index 21bd47240..17c97d0bc 100644 --- a/frontend/src/components/DataSources/Local/DropZoneForSmallLayouts.tsx +++ b/frontend/src/components/DataSources/Local/DropZoneForSmallLayouts.tsx @@ -142,7 +142,7 @@ export default function DropZoneForSmallLayouts() { uploadNextChunk(); }; - const { acceptedFiles, getRootProps, getInputProps } = useDropzone({ + const { getRootProps, getInputProps } = useDropzone({ accept: { 'application/pdf': ['.pdf'], 'image/*': ['.jpeg', '.jpg', '.png', '.svg'], @@ -214,7 +214,6 @@ export default function DropZoneForSmallLayouts() { setFilesData(copiedFilesData); } }; - console.log(acceptedFiles); return ( <>
    diff --git a/frontend/src/components/FileTable.tsx b/frontend/src/components/FileTable.tsx index aa4d9bb9a..2d0d690aa 100644 --- a/frontend/src/components/FileTable.tsx +++ b/frontend/src/components/FileTable.tsx @@ -43,7 +43,7 @@ import useServerSideEvent from '../hooks/useSse'; import { AxiosError } from 'axios'; import { XMarkIconOutline } from '@neo4j-ndl/react/icons'; import cancelAPI from '../services/CancelAPI'; -import IconButtonWithToolTip from './UI/IconButtonToolTip'; +import { IconButtonWithToolTip } from './UI/IconButtonToolTip'; import { batchSize, largeFileSize, llms } from '../utils/Constants'; import IndeterminateCheckbox from './UI/CustomCheckBox'; import { showErrorToast, showNormalToast } from '../utils/toasts'; diff --git a/frontend/src/components/Graph/CheckboxSelection.tsx b/frontend/src/components/Graph/CheckboxSelection.tsx index 7e3096daa..b335a4324 100644 --- a/frontend/src/components/Graph/CheckboxSelection.tsx +++ b/frontend/src/components/Graph/CheckboxSelection.tsx @@ -1,21 +1,31 @@ import { Checkbox } from '@neo4j-ndl/react'; import React from 'react'; import { CheckboxSectionProps } from '../../types'; -const CheckboxSelection: React.FC = ({ graphType, loading, handleChange }) => ( +import { graphLabels } from '../../utils/Constants'; + +const CheckboxSelection: React.FC = ({ graphType, loading, handleChange, isgds }) => (
    handleChange('DocumentChunk')} /> handleChange('Entities')} /> + {isgds && ( + handleChange('Communities')} + /> + )}
    ); diff --git a/frontend/src/components/Graph/GraphViewModal.tsx b/frontend/src/components/Graph/GraphViewModal.tsx index 4125c0d12..50c381685 100644 --- a/frontend/src/components/Graph/GraphViewModal.tsx +++ b/frontend/src/components/Graph/GraphViewModal.tsx @@ -30,7 +30,7 @@ import { MagnifyingGlassMinusIconOutline, MagnifyingGlassPlusIconOutline, } from '@neo4j-ndl/react/icons'; -import IconButtonWithToolTip from '../UI/IconButtonToolTip'; +import { IconButtonWithToolTip } from '../UI/IconButtonToolTip'; import { filterData, processGraphData, sortAlphabetically } from '../../utils/Utils'; import { useCredentials } from '../../context/UserCredentials'; import { LegendsChip } from './LegendsChip'; @@ -58,17 +58,17 @@ const GraphViewModal: React.FunctionComponent = ({ const nvlRef = useRef(null); const [nodes, setNodes] = useState([]); const [relationships, setRelationships] = useState([]); - const [graphType, setGraphType] = useState(intitalGraphType); const [allNodes, setAllNodes] = useState([]); const [allRelationships, setAllRelationships] = useState([]); const [loading, setLoading] = useState(false); const [status, setStatus] = useState<'unknown' | 'success' | 'danger'>('unknown'); const [statusMessage, setStatusMessage] = useState(''); - const { userCredentials } = useCredentials(); + const { userCredentials, isGdsActive } = useCredentials(); const [scheme, setScheme] = useState({}); const [newScheme, setNewScheme] = useState({}); const [searchQuery, setSearchQuery] = useState(''); const debouncedQuery = useDebounce(searchQuery, 300); + const [graphType, setGraphType] = useState(intitalGraphType(isGdsActive)); const [disableRefresh, setDisableRefresh] = useState(false); // the checkbox selection @@ -120,7 +120,7 @@ const GraphViewModal: React.FunctionComponent = ({ if (nvlRef.current) { nvlRef.current?.destroy(); } - setGraphType(intitalGraphType); + setGraphType(intitalGraphType(isGdsActive)); clearTimeout(timeoutId); setScheme({}); setNodes([]); @@ -182,6 +182,7 @@ const GraphViewModal: React.FunctionComponent = ({ useEffect(() => { if (open) { setLoading(true); + setGraphType(intitalGraphType(isGdsActive)); if (viewPoint !== 'chatInfoView') { graphApi(); } else { @@ -195,7 +196,31 @@ const GraphViewModal: React.FunctionComponent = ({ setLoading(false); } } - }, [open]); + }, [open, isGdsActive]); + + useEffect(() => { + handleSearch(debouncedQuery); + }, [debouncedQuery]); + + const initGraph = ( + graphType: GraphType[], + finalNodes: ExtendedNode[], + finalRels: Relationship[], + schemeVal: Scheme + ) => { + if (allNodes.length > 0 && allRelationships.length > 0) { + const { filteredNodes, filteredRelations, filteredScheme } = filterData( + graphType, + finalNodes ?? [], + finalRels ?? [], + schemeVal, + isGdsActive + ); + setNodes(filteredNodes); + setRelationships(filteredRelations); + setNewScheme(filteredScheme); + } + }; // The search and update nodes const handleSearch = useCallback( @@ -239,29 +264,6 @@ const GraphViewModal: React.FunctionComponent = ({ [nodes] ); - useEffect(() => { - handleSearch(debouncedQuery); - }, [debouncedQuery]); - - const initGraph = ( - graphType: GraphType[], - finalNodes: ExtendedNode[], - finalRels: Relationship[], - schemeVal: Scheme - ) => { - if (allNodes.length > 0 && allRelationships.length > 0) { - const { filteredNodes, filteredRelations, filteredScheme } = filterData( - graphType, - finalNodes ?? [], - finalRels ?? [], - schemeVal - ); - setNodes(filteredNodes); - setRelationships(filteredRelations); - setNewScheme(filteredScheme); - } - }; - // Unmounting the component if (!open) { return <>; @@ -308,7 +310,7 @@ const GraphViewModal: React.FunctionComponent = ({ setStatusMessage(''); setGraphViewOpen(false); setScheme({}); - setGraphType(intitalGraphType); + setGraphType(intitalGraphType(isGdsActive)); setNodes([]); setRelationships([]); setAllNodes([]); @@ -397,6 +399,7 @@ const GraphViewModal: React.FunctionComponent = ({ setNodes(updatedNodes); }; + // const isCommunity = allNodes.some(n=>n.labels.includes('__Community__')); return ( <> = ({ {headerTitle} {checkBoxView && ( - + n.labels.includes('__Community__'))} + /> )} @@ -430,7 +438,7 @@ const GraphViewModal: React.FunctionComponent = ({
    ) : nodes.length === 0 && relationships.length === 0 && graphType.length !== 0 ? (
    - +
    ) : graphType.length === 0 ? (
    diff --git a/frontend/src/components/Graph/LegendsChip.tsx b/frontend/src/components/Graph/LegendsChip.tsx index 2ab9c7b40..832150fad 100644 --- a/frontend/src/components/Graph/LegendsChip.tsx +++ b/frontend/src/components/Graph/LegendsChip.tsx @@ -1,6 +1,15 @@ import { LegendChipProps } from '../../types'; +import { graphLabels } from '../../utils/Constants'; import Legend from '../UI/Legend'; export const LegendsChip: React.FunctionComponent = ({ scheme, label, type, count, onClick }) => { - return ; + return ( + + ); }; diff --git a/frontend/src/components/Layout/Header.tsx b/frontend/src/components/Layout/Header.tsx index 345a004fd..acf62eefa 100644 --- a/frontend/src/components/Layout/Header.tsx +++ b/frontend/src/components/Layout/Header.tsx @@ -8,7 +8,7 @@ import { } from '@neo4j-ndl/react/icons'; import { Typography } from '@neo4j-ndl/react'; import { useCallback, useEffect } from 'react'; -import IconButtonWithToolTip from '../UI/IconButtonToolTip'; +import { IconButtonWithToolTip } from '../UI/IconButtonToolTip'; import { tooltips } from '../../utils/Constants'; import { useFileContext } from '../../context/UsersFiles'; diff --git a/frontend/src/components/Layout/SideNav.tsx b/frontend/src/components/Layout/SideNav.tsx index 89763737d..bdc43c8be 100644 --- a/frontend/src/components/Layout/SideNav.tsx +++ b/frontend/src/components/Layout/SideNav.tsx @@ -17,7 +17,7 @@ import ExpandedChatButtonContainer from '../ChatBot/ExpandedChatButtonContainer' import { APP_SOURCES, tooltips } from '../../utils/Constants'; import ChatModeToggle from '../ChatBot/ChatModeToggle'; import { RiChatSettingsLine } from 'react-icons/ri'; -import IconButtonWithToolTip from '../UI/IconButtonToolTip'; +import { IconButtonWithToolTip } from '../UI/IconButtonToolTip'; import GCSButton from '../DataSources/GCS/GCSButton'; import S3Component from '../DataSources/AWS/S3Bucket'; import WebButton from '../DataSources/Web/WebButton'; @@ -203,6 +203,7 @@ const SideNav: React.FC = ({ {!isChatModalOpen && ( { setchatModeAnchor(e.currentTarget); setshowChatMode(true); @@ -217,6 +218,7 @@ const SideNav: React.FC = ({ closeHandler={() => setshowChatMode(false)} menuAnchor={chatModeAnchor} disableBackdrop={true} + anchorPortal={true} > } diff --git a/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx b/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx index 8274e626a..0213e9502 100644 --- a/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx +++ b/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx @@ -41,7 +41,7 @@ export default function ConnectionModal({ const [username, setUsername] = useState(initialusername ?? 'neo4j'); const [password, setPassword] = useState(''); const [connectionMessage, setMessage] = useState({ type: 'unknown', content: '' }); - const { setUserCredentials, userCredentials } = useCredentials(); + const { setUserCredentials, userCredentials, setGdsActive } = useCredentials(); const [isLoading, setIsLoading] = useState(false); const [searchParams, setSearchParams] = useSearchParams(); const [userDbVectorIndex, setUserDbVectorIndex] = useState(initialuserdbvectorindex ?? undefined); @@ -84,7 +84,7 @@ export default function ConnectionModal({ JSON.stringify({ uri: usercredential?.uri, user: usercredential?.userName, - password: usercredential?.password, + password: btoa(usercredential?.password), database: usercredential?.database, userDbVectorIndex: 384, }) @@ -189,6 +189,7 @@ export default function ConnectionModal({ setMessage({ type: 'danger', content: 'Please drop a valid file' }); } } catch (err: any) { + console.log({ err }); setMessage({ type: 'danger', content: err.message }); } } @@ -206,14 +207,17 @@ export default function ConnectionModal({ if (response?.data?.status !== 'Success') { throw new Error(response.data.error); } else { + const isgdsActive = response.data.data.gds_status; + setGdsActive(isgdsActive); localStorage.setItem( 'neo4j.connection', JSON.stringify({ uri: connectionURI, user: username, - password: password, + password: btoa(password), database: database, userDbVectorIndex, + isgdsActive, }) ); setUserDbVectorIndex(response.data.data.db_vector_dimension); @@ -259,6 +263,7 @@ export default function ConnectionModal({ } } } catch (error) { + console.log({ error }); setIsLoading(false); if (error instanceof Error) { setMessage({ type: 'danger', content: error.message }); diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/index.tsx index 06e76ff8e..28114ced7 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/index.tsx @@ -3,11 +3,12 @@ import { POST_PROCESSING_JOBS } from '../../../../utils/Constants'; import { capitalize } from '../../../../utils/Utils'; import { useFileContext } from '../../../../context/UsersFiles'; import { tokens } from '@neo4j-ndl/base'; - +import { useCredentials } from '../../../../context/UserCredentials'; export default function PostProcessingCheckList() { const { breakpoints } = tokens; const tablet = useMediaQuery(`(min-width:${breakpoints.xs}) and (max-width: ${breakpoints.lg})`); const { postProcessingTasks, setPostProcessingTasks } = useFileContext(); + const { isGdsActive } = useCredentials(); return (
    @@ -18,29 +19,38 @@ export default function PostProcessingCheckList() { - {POST_PROCESSING_JOBS.map((job, idx) => ( - - - {job.title - .split('_') - .map((s) => capitalize(s)) - .join(' ')} - - } - checked={postProcessingTasks.includes(job.title)} - onChange={(e) => { - if (e.target.checked) { - setPostProcessingTasks((prev) => [...prev, job.title]); - } else { - setPostProcessingTasks((prev) => prev.filter((s) => s !== job.title)); + {POST_PROCESSING_JOBS.map((job, idx) => { + const isCreateCommunities = job.title === 'create_communities'; + return ( + + + {job.title + .split('_') + .map((s) => capitalize(s)) + .join(' ')} + } - }} - > - {job.description} - - ))} + checked={ + isCreateCommunities + ? isGdsActive && postProcessingTasks.includes(job.title) + : postProcessingTasks.includes(job.title) + } + onChange={(e) => { + if (e.target.checked) { + setPostProcessingTasks((prev) => [...prev, job.title]); + } else { + setPostProcessingTasks((prev) => prev.filter((s) => s !== job.title)); + } + }} + disabled={isCreateCommunities && !isGdsActive} + aria-label='checkbox-postProcessing' + /> + {job.description} + + ); + })}
    diff --git a/frontend/src/components/Popups/Settings/SchemaFromText.tsx b/frontend/src/components/Popups/Settings/SchemaFromText.tsx index 8ebc15020..914d9580c 100644 --- a/frontend/src/components/Popups/Settings/SchemaFromText.tsx +++ b/frontend/src/components/Popups/Settings/SchemaFromText.tsx @@ -27,7 +27,6 @@ const SchemaFromTextDialog = ({ try { setloading(true); const response = await getNodeLabelsAndRelTypesFromText(model, userText, isSchema); - console.log({ response }); setloading(false); if (response.data.status === 'Success') { if (response.data?.data?.labels.length) { diff --git a/frontend/src/components/UI/DatabaseIcon.tsx b/frontend/src/components/UI/DatabaseIcon.tsx new file mode 100644 index 000000000..ae291e401 --- /dev/null +++ b/frontend/src/components/UI/DatabaseIcon.tsx @@ -0,0 +1,25 @@ +import { CircleStackIconOutline, ScienceMoleculeIcon } from '@neo4j-ndl/react/icons'; +import { IconWithToolTip } from './IconButtonToolTip'; +import { DatabaseStatusProps } from '../../types'; +import { connectionLabels } from '../../utils/Constants'; + +const DatabaseStatusIcon: React.FC = ({ isConnected, isGdsActive, uri }) => { + const iconStyle = { fill: 'none', stroke: isConnected ? connectionLabels.greenStroke : connectionLabels.redStroke }; + const text = isGdsActive ? connectionLabels.graphDataScience : connectionLabels.graphDatabase; + return ( +
    + + + {isGdsActive ? ( + + ) : ( + + )} + + + {isConnected ? uri : connectionLabels.notConnected} +
    + ); +}; + +export default DatabaseStatusIcon; diff --git a/frontend/src/components/UI/DatabaseStatusIcon.tsx b/frontend/src/components/UI/DatabaseStatusIcon.tsx new file mode 100644 index 000000000..7b159607e --- /dev/null +++ b/frontend/src/components/UI/DatabaseStatusIcon.tsx @@ -0,0 +1,26 @@ +import { CircleStackIconOutline } from '@neo4j-ndl/react/icons'; +import { IconWithToolTip } from './IconButtonToolTip'; +import { DatabaseStatusProps } from '../../types'; +import { connectionLabels } from '../../utils/Constants'; +import ScienceMoleculeIcon from '../UI/ScienceMolecule'; + +const DatabaseStatusIcon: React.FC = ({ isConnected, isGdsActive, uri }) => { + const strokeColour = isConnected ? connectionLabels.greenStroke : connectionLabels.redStroke; + const text = isGdsActive ? connectionLabels.graphDataScience : connectionLabels.graphDatabase; + return ( +
    + + + {isGdsActive ? ( + + ) : ( + + )} + + + {isConnected ? uri : connectionLabels.notConnected} +
    + ); +}; + +export default DatabaseStatusIcon; diff --git a/frontend/src/components/UI/IconButtonToolTip.tsx b/frontend/src/components/UI/IconButtonToolTip.tsx index 9622fd8e2..5e7ecb47b 100644 --- a/frontend/src/components/UI/IconButtonToolTip.tsx +++ b/frontend/src/components/UI/IconButtonToolTip.tsx @@ -1,7 +1,7 @@ import { IconButton, Tip } from '@neo4j-ndl/react'; import { useState } from 'react'; -const IconButtonWithToolTip = ({ +export const IconButtonWithToolTip = ({ text, children, onClick, @@ -48,4 +48,27 @@ const IconButtonWithToolTip = ({ ); }; -export default IconButtonWithToolTip; +export const IconWithToolTip = ({ + text, + children, + placement = 'bottom', +}: { + label: string; + text: string | React.ReactNode; + children: React.ReactNode; + onClick?: React.MouseEventHandler | undefined; + size?: 'small' | 'medium' | 'large'; + clean?: boolean; + grouped?: boolean; + placement?: 'bottom' | 'top' | 'right' | 'left'; + disabled?: boolean; +}) => { + return ( + + {children} + + {text} + + + ); +}; diff --git a/frontend/src/components/UI/Menu.tsx b/frontend/src/components/UI/Menu.tsx index 4cfd1e238..62cc25095 100644 --- a/frontend/src/components/UI/Menu.tsx +++ b/frontend/src/components/UI/Menu.tsx @@ -1,6 +1,5 @@ import { Menu } from '@neo4j-ndl/react'; import { Menuitems, Origin } from '../../types'; - export default function CustomMenu({ open, closeHandler, @@ -23,25 +22,29 @@ export default function CustomMenu({ return ( { + closeHandler(); + }} anchorOrigin={anchorOrigin} transformOrigin={transformOrigin} anchorPortal={anchorPortal} anchorEl={MenuAnchor} disableBackdrop={disableBackdrop} + className='custom-menu' > - {items?.map((i, idx) => { - return ( - - ); - })} + {items?.map((i, idx) => ( + { + i.onClick(); + closeHandler(); + }} + disabled={i.disabledCondition} + className={i.isSelected ? i.selectedClassName : ''} + description={i.description} + /> + ))} ); } diff --git a/frontend/src/components/UI/ScienceMolecule.tsx b/frontend/src/components/UI/ScienceMolecule.tsx new file mode 100644 index 000000000..6cd046f14 --- /dev/null +++ b/frontend/src/components/UI/ScienceMolecule.tsx @@ -0,0 +1,40 @@ +import React from 'react'; + +interface ScienceMoleculeIconProps { + currentColour: string; +} + +const ScienceMoleculeIcon: React.FC = ({ currentColour }) => ( + + + + + +); + +export default ScienceMoleculeIcon; diff --git a/frontend/src/components/WebSources/GenericSourceButton.tsx b/frontend/src/components/WebSources/GenericSourceButton.tsx index 65c8b0046..96aab02ff 100644 --- a/frontend/src/components/WebSources/GenericSourceButton.tsx +++ b/frontend/src/components/WebSources/GenericSourceButton.tsx @@ -1,6 +1,6 @@ import { DataComponentProps } from '../../types'; import { Flex, Typography } from '@neo4j-ndl/react'; -import IconButtonWithToolTip from '../UI/IconButtonToolTip'; +import { IconButtonWithToolTip } from '../UI/IconButtonToolTip'; import { InformationCircleIconOutline } from '@neo4j-ndl/react/icons'; import { APP_SOURCES } from '../../utils/Constants'; import WebButton from '../DataSources/Web/WebButton'; diff --git a/frontend/src/context/UserCredentials.tsx b/frontend/src/context/UserCredentials.tsx index af13ea371..1b5eda2da 100644 --- a/frontend/src/context/UserCredentials.tsx +++ b/frontend/src/context/UserCredentials.tsx @@ -8,6 +8,8 @@ type Props = { export const UserConnection = createContext({ userCredentials: null, setUserCredentials: () => null, + isGdsActive: false, + setGdsActive: () => false, connectionStatus: false, setConnectionStatus: () => null, }); @@ -17,13 +19,17 @@ export const useCredentials = () => { }; const UserCredentialsWrapper: FunctionComponent = (props) => { const [userCredentials, setUserCredentials] = useState(null); + const [isGdsActive, setGdsActive] = useState(false); const [connectionStatus, setConnectionStatus] = useReducer((state) => !state, false); const value = { userCredentials, setUserCredentials, + isGdsActive, + setGdsActive, connectionStatus, setConnectionStatus, }; + return {props.children}; }; export default UserCredentialsWrapper; diff --git a/frontend/src/context/UsersFiles.tsx b/frontend/src/context/UsersFiles.tsx index fd3531403..fbab1b719 100644 --- a/frontend/src/context/UsersFiles.tsx +++ b/frontend/src/context/UsersFiles.tsx @@ -1,6 +1,6 @@ import { createContext, useContext, useState, Dispatch, SetStateAction, FC, useEffect } from 'react'; import { CustomFile, FileContextProviderProps, OptionType } from '../types'; -import { defaultLLM } from '../utils/Constants'; +import { chatModeLables, defaultLLM } from '../utils/Constants'; import { useCredentials } from './UserCredentials'; import Queue from '../utils/Queue'; interface showTextFromSchemaDialogType { @@ -58,7 +58,7 @@ const FileContextProvider: FC = ({ children }) => { const [selectedSchemas, setSelectedSchemas] = useState([]); const [rowSelection, setRowSelection] = useState>({}); const [selectedRows, setSelectedRows] = useState([]); - const [chatMode, setchatMode] = useState('graph+vector+fulltext'); + const [chatMode, setchatMode] = useState(chatModeLables.graph_vector_fulltext); const [isSchema, setIsSchema] = useState(false); const [showTextFromSchemaDialog, setShowTextFromSchemaDialog] = useState({ triggeredFrom: '', @@ -68,6 +68,7 @@ const FileContextProvider: FC = ({ children }) => { 'materialize_text_chunk_similarities', 'enable_hybrid_search_and_fulltext_search_in_bloom', 'materialize_entity_similarities', + 'create_communities', ]); const [processedCount, setProcessedCount] = useState(0); useEffect(() => { diff --git a/frontend/src/services/CancelAPI.ts b/frontend/src/services/CancelAPI.ts index de3ea9ba0..f491f06e0 100644 --- a/frontend/src/services/CancelAPI.ts +++ b/frontend/src/services/CancelAPI.ts @@ -9,7 +9,7 @@ const cancelAPI = async (filenames: string[], source_types: string[]) => { formData.append('uri', credentials?.uri ?? ''); formData.append('database', credentials?.database ?? ''); formData.append('userName', credentials?.user ?? ''); - formData.append('password', credentials?.password ?? ''); + formData.append('password', atob(credentials?.password) ?? ''); } formData.append('filenames', JSON.stringify(filenames)); formData.append('source_types', JSON.stringify(source_types)); diff --git a/frontend/src/services/ChunkEntitiesInfo.ts b/frontend/src/services/ChunkEntitiesInfo.ts index aa133c815..f69ddd3aa 100644 --- a/frontend/src/services/ChunkEntitiesInfo.ts +++ b/frontend/src/services/ChunkEntitiesInfo.ts @@ -1,13 +1,20 @@ import { ChatInfo_APIResponse, UserCredentials } from '../types'; import api from '../API/Index'; -const chunkEntitiesAPI = async (userCredentials: UserCredentials, chunk_ids: string) => { +const chunkEntitiesAPI = async ( + userCredentials: UserCredentials, + chunk_ids: string, + database: string = 'neo4j', + is_entity: boolean = false +) => { try { const formData = new FormData(); formData.append('uri', userCredentials?.uri ?? ''); formData.append('userName', userCredentials?.userName ?? ''); formData.append('password', userCredentials?.password ?? ''); formData.append('chunk_ids', chunk_ids); + formData.append('database', database); + formData.append('is_entity', String(is_entity)); const response: ChatInfo_APIResponse = await api.post(`/chunk_entities`, formData, { headers: { diff --git a/frontend/src/types.ts b/frontend/src/types.ts index d16f56fa1..9631335a9 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -223,6 +223,7 @@ export interface Messages { cypher_query?: string; graphonly_entities?: []; error?: string; + entities?: chunk[]; } export type ChatbotProps = { @@ -245,7 +246,7 @@ export interface GraphViewModalProps { selectedRows?: CustomFile[] | undefined; } -export type GraphType = 'Entities' | 'DocumentChunk'; +export type GraphType = 'Entities' | 'DocumentChunk' | 'Communities'; export type PartialLabelNode = Partial & { labels: string; @@ -255,6 +256,7 @@ export interface CheckboxSectionProps { graphType: GraphType[]; loading: boolean; handleChange: (graph: GraphType) => void; + isgds: boolean; } export interface fileName { @@ -463,7 +465,13 @@ export type Entity = { id: string; }; }; - +export type Community = { + id: string; + summary: string; + weight: number; + level: number; + community_rank: number; +}; export type GroupedEntity = { texts: Set; color: string; @@ -501,6 +509,7 @@ export interface Chunk { url?: string; fileSource: string; score?: string; + fileType: string; } export interface SpeechSynthesisProps { @@ -525,7 +534,7 @@ export interface SettingsModalProps { onClear?: () => void; } export interface Menuitems { - title: string; + title: string | JSX.Element; onClick: () => void; disabledCondition: boolean; description?: string | React.ReactNode; @@ -620,6 +629,8 @@ export interface DrawerChatbotProps { export interface ContextProps { userCredentials: UserCredentials | null; setUserCredentials: (UserCredentials: UserCredentials) => void; + isGdsActive: boolean; + setGdsActive: Dispatch>; connectionStatus: boolean; setConnectionStatus: Dispatch>; } @@ -627,3 +638,33 @@ export interface MessageContextType { messages: Messages[] | []; setMessages: Dispatch>; } + +export interface DatabaseStatusProps { + isConnected: boolean; + isGdsActive: boolean; + uri: string | null; +} + +export type SourcesProps = { + loading: boolean; + mode: string; + sources: string[]; + chunks: Chunk[]; +}; + +export type ChunkProps = { + loading: boolean; + chunks: Chunk[]; +}; + +export type EntitiesProps = { + loading: boolean; + mode: string; + graphonly_entities: []; + infoEntities: Entity[]; +}; + +export type CommunitiesProps = { + loading: boolean; + communities: Community[]; +}; diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index 114b20fa0..0b2f60cba 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -1,5 +1,6 @@ import { NvlOptions } from '@neo4j-nvl/base'; import { GraphType, OptionType } from '../types'; +import { getDescriptionForChatMode } from './Utils'; export const document = `+ [docs]`; @@ -28,10 +29,12 @@ export const docChunkEntities = `+[chunks] + collect { MATCH p=(c)-[:SIMILAR]-() RETURN p } // similar-chunks //chunks with entities + collect { OPTIONAL MATCH p=(c:Chunk)-[:HAS_ENTITY]->(e)-[*0..1]-(:!Chunk) RETURN p }`; + export const APP_SOURCES = process.env.VITE_REACT_APP_SOURCES !== '' ? (process.env.VITE_REACT_APP_SOURCES?.split(',') as string[]) : ['gcs', 's3', 'local', 'wiki', 'youtube', 'web']; + export const llms = process.env?.VITE_LLM_MODELS?.trim() != '' ? (process.env.VITE_LLM_MODELS?.split(',') as string[]) @@ -56,10 +59,60 @@ export const defaultLLM = llms?.includes('openai-gpt-4o') : llms?.includes('gemini-1.0-pro') ? 'gemini-1.0-pro' : 'diffbot'; + +// export const chatModes = +// process.env?.VITE_CHAT_MODES?.trim() != '' +// ? process.env.VITE_CHAT_MODES?.split(',') +// : ['vector', 'graph', 'graph+vector', 'fulltext', 'graph+vector+fulltext', 'local community', 'global community']; + +export const chatModeLables = { + vector: 'vector', + graph : 'graph', + graph_vector: 'graph+vector', + fulltext: 'fulltext', + graph_vector_fulltext: 'graph+vector+fulltext', + entity_vector:'entity search+vector', + unavailableChatMode: 'Chat mode is unavailable when rows are selected', + selected:'Selected' +} export const chatModes = process.env?.VITE_CHAT_MODES?.trim() != '' - ? process.env.VITE_CHAT_MODES?.split(',') - : ['vector', 'graph', 'graph+vector', 'fulltext', 'graph+vector+fulltext']; + ? process.env.VITE_CHAT_MODES?.split(',').map((mode) => ({ + mode: mode.trim(), + description: getDescriptionForChatMode(mode.trim()), + })) + : [ + { + mode: chatModeLables.vector, + description: 'Performs semantic similarity search on text chunks using vector indexing.', + }, + { + mode: chatModeLables.graph, + description: + 'Translates text to Cypher queries for precise data retrieval from a graph database.' + }, + { + mode: chatModeLables.graph_vector, + description: + 'Combines vector indexing and graph connections for contextually enhanced semantic search.', + }, + { + mode: chatModeLables.fulltext, + description: + 'Conducts fast, keyword-based search using full-text indexing on text chunks.', + }, + { + mode: chatModeLables.graph_vector_fulltext, + description: + 'Integrates vector, graph, and full-text indexing for comprehensive search results.', + }, + { + mode: chatModeLables.entity_vector, + description: + 'Uses vector indexing on entity nodes for highly relevant entity-based search.', + }, + ]; + export const chunkSize = process.env.VITE_CHUNK_SIZE ? parseInt(process.env.VITE_CHUNK_SIZE) : 1 * 1024 * 1024; export const timeperpage = process.env.VITE_TIME_PER_PAGE ? parseInt(process.env.VITE_TIME_PER_PAGE) : 50; export const timePerByte = 0.2; @@ -184,6 +237,10 @@ export const POST_PROCESSING_JOBS: { title: string; description: string }[] = [ semantic meaning. This facilitates tasks like clustering similar entities, identifying duplicates, and performing similarity-based searches.`, }, + { + title: 'create_communities', + description: 'Create Communities identifies and groups similar entities, improving search accuracy and analysis.', + }, ]; export const RETRY_OPIONS = [ 'start_from_beginning', @@ -215,7 +272,12 @@ export const graphView: OptionType[] = [ { label: 'Entity Graph', value: queryMap.Entities }, { label: 'Knowledge Graph', value: queryMap.DocChunkEntities }, ]; -export const intitalGraphType: GraphType[] = ['DocumentChunk', 'Entities']; + +export const intitalGraphType = (isGDSActive: boolean): GraphType[] => { + return isGDSActive + ? ['DocumentChunk', 'Entities', 'Communities'] // GDS is active, include communities + : ['DocumentChunk', 'Entities']; // GDS is inactive, exclude communities +}; export const appLabels = { ownSchema: 'Or Define your own Schema', @@ -237,6 +299,17 @@ export const graphLabels = { selectCheckbox: 'Select atleast one checkbox for graph view', totalRelationships: 'Total Relationships', nodeSize: 30, + docChunk: 'Document & Chunk', + community: 'Communities', + noNodesRels: 'No Nodes and No relationships', }; export const RESULT_STEP_SIZE = 25; + +export const connectionLabels = { + notConnected: 'Not Connected', + graphDataScience: 'Graph Data Science', + graphDatabase: 'Graph Database', + greenStroke: 'green', + redStroke: 'red', +}; diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index 8b49c7e7d..97e7bda07 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -11,6 +11,15 @@ import { SourceNode, UserCredentials, } from '../types'; +import Wikipediadarkmode from '../assets/images/wikipedia-darkmode.svg'; +import Wikipediadlogo from '../assets/images/wikipedia.svg'; +import webdarklogo from '../assets/images/web-darkmode.svg'; +import weblogo from '../assets/images/web.svg'; +import youtubedarklogo from '../assets/images/youtube-darkmode.svg'; +import youtubelightlogo from '../assets/images/youtube-lightmode.svg'; +import s3logo from '../assets/images/s3logo.png'; +import gcslogo from '../assets/images/gcs.webp'; +import { chatModeLables } from './Constants'; // Get the Url export const url = () => { @@ -181,18 +190,34 @@ export const processGraphData = (neoNodes: ExtendedNode[], neoRels: ExtendedRela return { finalNodes, finalRels, schemeVal }; }; +/** + * Filters nodes, relationships, and scheme based on the selected graph types. + * + * @param graphType - An array of graph types to filter by (e.g., 'DocumentChunk', 'Entities', 'Communities'). + * @param allNodes - An array of all nodes present in the graph. + * @param allRelationships - An array of all relationships in the graph. + * @param scheme - The scheme object containing node and relationship information. + * @returns An object containing filtered nodes, relationships, and scheme based on the selected graph types. + */ export const filterData = ( graphType: GraphType[], allNodes: ExtendedNode[], allRelationships: Relationship[], - scheme: Scheme + scheme: Scheme, + isGdsActive: boolean ) => { let filteredNodes: ExtendedNode[] = []; let filteredRelations: Relationship[] = []; let filteredScheme: Scheme = {}; - const entityTypes = Object.keys(scheme).filter((type) => type !== 'Document' && type !== 'Chunk'); - if (graphType.includes('DocumentChunk') && !graphType.includes('Entities')) { - // Document + Chunk + const entityTypes = Object.keys(scheme).filter( + (type) => type !== 'Document' && type !== 'Chunk' && type !== '__Community__' + ); + // Only Document + Chunk + if ( + graphType.includes('DocumentChunk') && + !graphType.includes('Entities') && + (!graphType.includes('Communities') || !isGdsActive) + ) { filteredNodes = allNodes.filter( (node) => (node.labels.includes('Document') && node.properties.fileName) || node.labels.includes('Chunk') ); @@ -204,8 +229,12 @@ export const filterData = ( nodeIds.has(rel.to) ); filteredScheme = { Document: scheme.Document, Chunk: scheme.Chunk }; - } else if (graphType.includes('Entities') && !graphType.includes('DocumentChunk')) { // Only Entity + } else if ( + graphType.includes('Entities') && + !graphType.includes('DocumentChunk') && + (!graphType.includes('Communities') || !isGdsActive) + ) { const entityNodes = allNodes.filter((node) => !node.labels.includes('Document') && !node.labels.includes('Chunk')); filteredNodes = entityNodes ? entityNodes : []; const nodeIds = new Set(filteredNodes.map((node) => node.id)); @@ -216,15 +245,100 @@ export const filterData = ( nodeIds.has(rel.to) ); filteredScheme = Object.fromEntries(entityTypes.map((key) => [key, scheme[key]])) as Scheme; - } else if (graphType.includes('DocumentChunk') && graphType.includes('Entities')) { + // Only Communities + } else if ( + graphType.includes('Communities') && + !graphType.includes('DocumentChunk') && + !graphType.includes('Entities') && + isGdsActive + ) { + filteredNodes = allNodes.filter((node) => node.labels.includes('__Community__')); + const nodeIds = new Set(filteredNodes.map((node) => node.id)); + filteredRelations = allRelationships.filter( + (rel) => + ['IN_COMMUNITY', 'PARENT_COMMUNITY'].includes(rel.caption ?? '') && nodeIds.has(rel.from) && nodeIds.has(rel.to) + ); + filteredScheme = { __Community__: scheme.__Community__ }; // Document + Chunk + Entity + } else if ( + graphType.includes('DocumentChunk') && + graphType.includes('Entities') && + (!graphType.includes('Communities') || !isGdsActive) + ) { + filteredNodes = allNodes.filter( + (node) => + (node.labels.includes('Document') && node.properties.fileName) || + node.labels.includes('Chunk') || + (!node.labels.includes('Document') && !node.labels.includes('Chunk') && !node.labels.includes('__Community__')) + ); + const nodeIds = new Set(filteredNodes.map((node) => node.id)); + filteredRelations = allRelationships.filter( + (rel) => + !['IN_COMMUNITY', 'PARENT_COMMUNITY'].includes(rel.caption ?? '') && + nodeIds.has(rel.from) && + nodeIds.has(rel.to) + ); + filteredScheme = { + Document: scheme.Document, + Chunk: scheme.Chunk, + ...Object.fromEntries(entityTypes.map((key) => [key, scheme[key]])), + }; + // Entities + Communities + } else if ( + graphType.includes('Entities') && + graphType.includes('Communities') && + !graphType.includes('DocumentChunk') && + isGdsActive + ) { + const entityNodes = allNodes.filter((node) => !node.labels.includes('Document') && !node.labels.includes('Chunk')); + const communityNodes = allNodes.filter((node) => node.labels.includes('__Community__')); + filteredNodes = [...entityNodes, ...communityNodes]; + const nodeIds = new Set(filteredNodes.map((node) => node.id)); + filteredRelations = allRelationships.filter( + (rel) => + !['PART_OF', 'FIRST_CHUNK', 'SIMILAR', 'NEXT_CHUNK'].includes(rel.caption ?? '') && + nodeIds.has(rel.from) && + nodeIds.has(rel.to) + ); + filteredScheme = { + ...Object.fromEntries(entityTypes.map((key) => [key, scheme[key]])), + __Community__: scheme.__Community__, + }; + // Document + Chunk + Communities + } else if ( + graphType.includes('DocumentChunk') && + graphType.includes('Communities') && + !graphType.includes('Entities') && + isGdsActive + ) { + const documentChunkNodes = allNodes.filter( + (node) => (node.labels.includes('Document') && node.properties.fileName) || node.labels.includes('Chunk') + ); + const communityNodes = allNodes.filter((node) => node.labels.includes('__Community__')); + filteredNodes = [...documentChunkNodes, ...communityNodes]; + const nodeIds = new Set(filteredNodes.map((node) => node.id)); + filteredRelations = allRelationships.filter( + (rel) => + ['PART_OF', 'FIRST_CHUNK', 'SIMILAR', 'NEXT_CHUNK', 'IN_COMMUNITY', 'PARENT_COMMUNITY'].includes( + rel.caption ?? '' + ) && + nodeIds.has(rel.from) && + nodeIds.has(rel.to) + ); + filteredScheme = { Document: scheme.Document, Chunk: scheme.Chunk, __Community__: scheme.__Community__ }; + // Document + Chunk + Entity + Communities (All types) + } else if ( + graphType.includes('DocumentChunk') && + graphType.includes('Entities') && + graphType.includes('Communities') && + isGdsActive + ) { filteredNodes = allNodes; filteredRelations = allRelationships; filteredScheme = scheme; } return { filteredNodes, filteredRelations, filteredScheme }; }; - export const getDateTime = () => { const date = new Date(); const formattedDateTime = `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`; @@ -246,8 +360,11 @@ export const capitalize = (word: string): string => { }; export const parseEntity = (entity: Entity) => { const { labels, properties } = entity; - const [label] = labels; + let [label] = labels; const text = properties.id; + if (!label) { + label = 'Entity'; + } return { label, text }; }; @@ -289,3 +406,66 @@ export const sortAlphabetically = (a: Relationship, b: Relationship) => { const captionTwo = b.caption?.toLowerCase() || ''; return captionOne.localeCompare(captionTwo); }; + +export const capitalizeWithPlus = (s: string) => { + return s + .split('+') + .map((s) => capitalize(s)) + .join('+'); +}; + +export const getDescriptionForChatMode = (mode: string): string => { + switch (mode.toLowerCase()) { + case chatModeLables.vector: + return 'Utilizes vector indexing on text chunks to enable semantic similarity search.'; + case chatModeLables.graph: + return 'Leverages text-to-cypher translation to query a database and retrieve relevant data, ensuring a highly targeted and contextually accurate response.'; + case chatModeLables.graph_vector: + return 'Combines vector indexing on text chunks with graph connections, enhancing search results with contextual relevance by considering relationships between concepts.'; + case chatModeLables.fulltext: + return 'Employs a fulltext index on text chunks for rapid keyword-based search, efficiently identifying documents containing specific words or phrases.'; + case chatModeLables.graph_vector_fulltext: + return 'Merges vector indexing, graph connections, and fulltext indexing for a comprehensive search approach, combining semantic similarity, contextual relevance, and keyword-based search for optimal results.'; + case chatModeLables.entity_vector: + return 'Combines entity node vector indexing with graph connections for accurate entity-based search, providing the most relevant response.'; + default: + return 'Chat mode description not available'; // Fallback description + } +}; +export const getLogo = (mode: string): Record => { + if (mode === 'light') { + return { + Wikipedia: Wikipediadarkmode, + 'web-url': webdarklogo, + 's3 bucket': s3logo, + youtube: youtubedarklogo, + 'gcs bucket': gcslogo, + }; + } + return { + Wikipedia: Wikipediadlogo, + 'web-url': weblogo, + 's3 bucket': s3logo, + youtube: youtubelightlogo, + 'gcs bucket': gcslogo, + }; +}; + +export const generateYouTubeLink = (url: string, startTime: string) => { + try { + const urlObj = new URL(url); + urlObj.searchParams.set('t', startTime); + return urlObj.toString(); + } catch (error) { + console.error('Invalid URL:', error); + return ''; + } +}; +export function isAllowedHost(url: string, allowedHosts: string[]) { + try { + const parsedUrl = new URL(url); + return allowedHosts.includes(parsedUrl.host); + } catch (e) { + return false; + } +} From cc62f5081c8e2e33e391e729ecaf9f86530c600d Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Fri, 20 Sep 2024 06:23:27 +0000 Subject: [PATCH 114/292] added global env for communities --- backend/src/graphDB_dataAccess.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/backend/src/graphDB_dataAccess.py b/backend/src/graphDB_dataAccess.py index 279451bdf..643902b16 100644 --- a/backend/src/graphDB_dataAccess.py +++ b/backend/src/graphDB_dataAccess.py @@ -7,6 +7,9 @@ from src.shared.constants import BUCKET_UPLOAD from src.entities.source_node import sourceNode import json +from dotenv import load_dotenv + +load_dotenv() class graphDBdataAccess: @@ -152,11 +155,14 @@ def check_gds_version(self): result = self.graph.query(gds_procedure_count) total_gds_procedures = result[0]['totalGdsProcedures'] if result else 0 - if total_gds_procedures > 0: + enable_communities = os.environ.get('ENABLE_COMMUNITIES','').upper() == "TRUE" + logging.info(f"Enable Communities {enable_communities}") + + if enable_communities and total_gds_procedures > 0: logging.info("GDS is available in the database.") return True else: - logging.info("GDS is not available in the database.") + logging.info("Communities are disabled or GDS is not available in the database.") return False except Exception as e: logging.error(f"An error occurred while checking GDS version: {e}") From 3732c381fcaf11c953afc0b2cf9ce2e2e1332444 Mon Sep 17 00:00:00 2001 From: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Date: Fri, 20 Sep 2024 06:44:19 +0000 Subject: [PATCH 115/292] comment all security header --- backend/score.py | 5 +++++ backend/src/main.py | 16 ++++++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/backend/score.py b/backend/score.py index e87fc618e..227ff2901 100644 --- a/backend/score.py +++ b/backend/score.py @@ -48,6 +48,11 @@ def sick(): return False app = FastAPI() +# SecWeb(app=app, Option={'referrer': False, 'xframe': False}) +# app.add_middleware(HSTS, Option={'max-age': 4}) +# app.add_middleware(ContentSecurityPolicy, Option={'default-src': ["'self'"], 'base-uri': ["'self'"], 'block-all-mixed-content': []}, script_nonce=False, style_nonce=False, report_only=False) +# app.add_middleware(XContentTypeOptions) +# app.add_middleware(XFrame, Option={'X-Frame-Options': 'DENY'}) app.add_middleware( CORSMiddleware, diff --git a/backend/src/main.py b/backend/src/main.py index 8bae03809..49906aea8 100644 --- a/backend/src/main.py +++ b/backend/src/main.py @@ -142,20 +142,20 @@ def create_source_node_graph_url_youtube(graph, model, source_url, source_type): obj_source_node.created_at = datetime.now() match = re.search(r'(?:v=)([0-9A-Za-z_-]{11})\s*',obj_source_node.url) logging.info(f"match value: {match}") - cred_path = os.path.join(os.getcwd(),"llm-experiments_credentials.json") - print(f'Credential file path {cred_path}') - if os.path.exists(cred_path): + file_path = os.path.join(os.path.dirname(__file__),"llm-experiments_credentials.json") + logging.info(f'Credential file path {file_path}') + if os.path.exists(file_path): logging.info("File path exist") - with open(cred_path,'r') as secret_file: - secret_data = json.load(secret_file) - logging.info(f"Project id : {secret_data['project_id']}") - logging.info(f"Universal domain: {secret_data['universe_domain']}") + with open(file_path,'r') as file: + data = json.load(file) + logging.info(f"Project id : {data['project_id']}") + logging.info(f"Universal domain: {data['universe_domain']}") else: logging.warning("credntial file path not exist") video_id = parse_qs(urlparse(youtube_url).query).get('v') print(f'Video Id Youtube: {video_id}') - google_api_client = GoogleApiClient(service_account_path=Path(cred_path)) + google_api_client = GoogleApiClient(service_account_path=Path(file_path)) youtube_loader_channel = GoogleApiYoutubeLoader( google_api_client=google_api_client, video_ids=[video_id[0].strip()], add_video_info=True From 763dedf7c0e11c7bccb77bc7ae9f850f586202f7 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Fri, 20 Sep 2024 14:59:18 +0530 Subject: [PATCH 116/292] added threading to chat summarization to improve chat response time (#751) --- backend/src/QA_integration.py | 44 ++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/backend/src/QA_integration.py b/backend/src/QA_integration.py index 7ac99f66b..651440437 100644 --- a/backend/src/QA_integration.py +++ b/backend/src/QA_integration.py @@ -1,11 +1,14 @@ import os import json -from datetime import datetime import time -from typing import Any +import logging +import threading +from concurrent.futures import ThreadPoolExecutor +from datetime import datetime +from typing import Any from dotenv import load_dotenv -import logging + # LangChain imports from langchain_community.vectorstores.neo4j_vector import Neo4jVector @@ -364,22 +367,26 @@ def setup_chat(model, graph, document_names, chat_mode_settings): return llm, doc_retriever, model_name -def process_chat_response(messages,history, question, model, graph, document_names,chat_mode_settings): +def process_chat_response(messages, history, question, model, graph, document_names, chat_mode_settings): try: - llm, doc_retriever, model_version = setup_chat(model, graph, document_names,chat_mode_settings) + llm, doc_retriever, model_version = setup_chat(model, graph, document_names, chat_mode_settings) docs = retrieve_documents(doc_retriever, messages) if docs: - content, result, total_tokens = process_documents(docs, question, messages, llm, model,chat_mode_settings) + content, result, total_tokens = process_documents(docs, question, messages, llm, model, chat_mode_settings) else: content = "I couldn't find any relevant documents to answer your question." - result = {"sources": [], "chunkdetails": [],"entities":[]} + result = {"sources": [], "chunkdetails": [], "entities": []} total_tokens = 0 ai_response = AIMessage(content=content) messages.append(ai_response) - summarize_and_log(history, messages, llm) - + + summarization_thread = threading.Thread(target=summarize_and_log, args=(history, messages, llm)) + summarization_thread.start() + logging.info("Summarization thread started.") + # summarize_and_log(history, messages, llm) + return { "session_id": "", "message": content, @@ -390,7 +397,7 @@ def process_chat_response(messages,history, question, model, graph, document_nam "total_tokens": total_tokens, "response_time": 0, "mode": chat_mode_settings["mode"], - "entities" : result["entities"] + "entities": result["entities"] }, "user": "chatbot" } @@ -413,6 +420,7 @@ def process_chat_response(messages,history, question, model, graph, document_nam } def summarize_and_log(history, stored_messages, llm): + logging.info("Starting summarization in a separate thread.") if not stored_messages: logging.info("No messages to summarize.") return False @@ -433,9 +441,10 @@ def summarize_and_log(history, stored_messages, llm): summary_message = summarization_chain.invoke({"chat_history": stored_messages}) - history.clear() - history.add_user_message("Our current conversation summary till now") - history.add_message(summary_message) + with threading.Lock(): + history.clear() + history.add_user_message("Our current conversation summary till now") + history.add_message(summary_message) history_summarized_time = time.time() - start_time logging.info(f"Chat History summarized in {history_summarized_time:.2f} seconds") @@ -443,8 +452,8 @@ def summarize_and_log(history, stored_messages, llm): return True except Exception as e: - logging.error(f"An error occurred while summarizing messages: {e}") - return False + logging.error(f"An error occurred while summarizing messages: {e}", exc_info=True) + return False def create_graph_chain(model, graph): try: @@ -501,7 +510,10 @@ def process_graph_response(model, graph, question, messages, history): ai_response = AIMessage(content=ai_response_content) messages.append(ai_response) - summarize_and_log(history, messages, qa_llm) + # summarize_and_log(history, messages, qa_llm) + summarization_thread = threading.Thread(target=summarize_and_log, args=(history, messages, qa_llm)) + summarization_thread.start() + logging.info("Summarization thread started.") result = { "session_id": "", From 27272f479e025417dc98348b20d2df077f46b991 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Fri, 20 Sep 2024 14:59:39 +0530 Subject: [PATCH 117/292] formatted the queries and added logic for empty label (#752) --- backend/src/shared/constants.py | 190 ++++++++++++++++++++++++-------- 1 file changed, 141 insertions(+), 49 deletions(-) diff --git a/backend/src/shared/constants.py b/backend/src/shared/constants.py index 7856dbec2..bbf579520 100644 --- a/backend/src/shared/constants.py +++ b/backend/src/shared/constants.py @@ -235,51 +235,97 @@ LOCAL_COMMUNITY_TOP_OUTSIDE_RELS = 10 LOCAL_COMMUNITY_SEARCH_QUERY = """ -WITH collect(node) as nodes, avg(score) as score, collect({{id: elementId(node), score:score}}) as metadata -WITH score, nodes,metadata, -collect {{ - UNWIND nodes as n - MATCH (n)<-[:HAS_ENTITY]->(c:Chunk) - WITH c, count(distinct n) as freq - RETURN c - ORDER BY freq DESC - LIMIT {topChunks} -}} AS chunks, -collect {{ - UNWIND nodes as n - MATCH (n)-[:IN_COMMUNITY]->(c:__Community__) - WITH c, c.community_rank as rank, c.weight AS weight - RETURN c - ORDER BY rank, weight DESC - LIMIT {topCommunities} -}} AS communities, -collect {{ - unwind nodes as n - unwind nodes as m - match (n)-[r]->(m) - RETURN distinct r - // todo should we have a limit here? -}} as rels, -collect {{ - unwind nodes as n - match path = (n)-[r]-(m:__Entity__) - where not m in nodes - with m, collect(distinct r) as rels, count(*) as freq - ORDER BY freq DESC LIMIT {topOutsideRels} - WITH collect(m) as outsideNodes, apoc.coll.flatten(collect(rels)) as rels - RETURN {{ nodes: outsideNodes, rels: rels }} -}} as outside +WITH collect(node) AS nodes, + avg(score) AS score, + collect({{id: elementId(node), score: score}}) AS metadata + +WITH score, nodes, metadata, + + collect {{ + UNWIND nodes AS n + MATCH (n)<-[:HAS_ENTITY]->(c:Chunk) + WITH c, count(distinct n) AS freq + RETURN c + ORDER BY freq DESC + LIMIT {topChunks} + }} AS chunks, + + collect {{ + UNWIND nodes AS n + MATCH (n)-[:IN_COMMUNITY]->(c:__Community__) + WITH c, c.community_rank AS rank, c.weight AS weight + RETURN c + ORDER BY rank, weight DESC + LIMIT {topCommunities} + }} AS communities, + + collect {{ + UNWIND nodes AS n + UNWIND nodes AS m + MATCH (n)-[r]->(m) + RETURN DISTINCT r + // TODO: need to add limit + }} AS rels, + + collect {{ + UNWIND nodes AS n + MATCH path = (n)-[r]-(m:__Entity__) + WHERE NOT m IN nodes + WITH m, collect(distinct r) AS rels, count(*) AS freq + ORDER BY freq DESC + LIMIT {topOutsideRels} + WITH collect(m) AS outsideNodes, apoc.coll.flatten(collect(rels)) AS rels + RETURN {{ nodes: outsideNodes, rels: rels }} + }} AS outside """ LOCAL_COMMUNITY_SEARCH_QUERY_SUFFIX = """ -RETURN {chunks: [c in chunks | c.text], - communities: [c in communities | c.summary], - entities: [n in nodes | apoc.coll.removeAll(labels(n),["__Entity__"])[0] + ":"+ n.id + " " + coalesce(n.description, "")], - relationships: [r in rels | startNode(r).id+" "+type(r)+" "+endNode(r).id], - outside: { - nodes: [n in outside[0].nodes | apoc.coll.removeAll(labels(n),["__Entity__"])[0] + ":"+n.id + " " + coalesce(n.description, "")], - relationships: [r in outside[0].rels | apoc.coll.removeAll(labels(startNode(r)),["__Entity__"])[0] + ":"+startNode(r).id+" "+type(r)+" "+apoc.coll.removeAll(labels(startNode(r)),["__Entity__"])[0] + ":"+endNode(r).id]} - } AS text, score, {entities:metadata} as metadata +RETURN { + chunks: [c IN chunks | c.text], + communities: [c IN communities | c.summary], + entities: [ + n IN nodes | + CASE + WHEN size(labels(n)) > 1 THEN + apoc.coll.removeAll(labels(n), ["__Entity__"])[0] + ":" + n.id + " " + coalesce(n.description, "") + ELSE + n.id + " " + coalesce(n.description, "") + END + ], + relationships: [ + r IN rels | + startNode(r).id + " " + type(r) + " " + endNode(r).id + ], + outside: { + nodes: [ + n IN outside[0].nodes | + CASE + WHEN size(labels(n)) > 1 THEN + apoc.coll.removeAll(labels(n), ["__Entity__"])[0] + ":" + n.id + " " + coalesce(n.description, "") + ELSE + n.id + " " + coalesce(n.description, "") + END + ], + relationships: [ + r IN outside[0].rels | + CASE + WHEN size(labels(startNode(r))) > 1 THEN + apoc.coll.removeAll(labels(startNode(r)), ["__Entity__"])[0] + ":" + startNode(r).id + " " + ELSE + startNode(r).id + " " + END + + type(r) + " " + + CASE + WHEN size(labels(endNode(r))) > 1 THEN + apoc.coll.removeAll(labels(endNode(r)), ["__Entity__"])[0] + ":" + endNode(r).id + ELSE + endNode(r).id + END + ] + } +} AS text, +score, +{entities: metadata} AS metadata """ LOCAL_COMMUNITY_DETAILS_QUERY_PREFIX = """ @@ -289,14 +335,60 @@ """ LOCAL_COMMUNITY_DETAILS_QUERY_SUFFIX = """ WITH * -UNWIND chunks as c +UNWIND chunks AS c MATCH (c)-[:PART_OF]->(d:Document) -RETURN [c {.*, embedding:null, fileName:d.fileName, fileSource:d.fileSource}] as chunks, -[community in communities | community {.*, embedding:null}] as communities, -[node in nodes+outside[0].nodes | {element_id:elementId(node), labels:labels(node), properties:{id:node.id,description:node.description}}] as nodes, -[r in rels+outside[0].rels | {startNode:{element_id:elementId(startNode(r)), labels:labels(startNode(r)), properties:{id:startNode(r).id,description:startNode(r).description}}, - endNode:{element_id:elementId(endNode(r)), labels:labels(endNode(r)), properties:{id:endNode(r).id,description:endNode(r).description}}, - relationship: {type:type(r), element_id:elementId(r)}}] as entities +RETURN + [ + c { + .*, + embedding: null, + fileName: d.fileName, + fileSource: d.fileSource + } + ] AS chunks, + [ + community IN communities | + community { + .*, + embedding: null + } + ] AS communities, + [ + node IN nodes + outside[0].nodes | + { + element_id: elementId(node), + labels: labels(node), + properties: { + id: node.id, + description: node.description + } + } + ] AS nodes, + [ + r IN rels + outside[0].rels | + { + startNode: { + element_id: elementId(startNode(r)), + labels: labels(startNode(r)), + properties: { + id: startNode(r).id, + description: startNode(r).description + } + }, + endNode: { + element_id: elementId(endNode(r)), + labels: labels(endNode(r)), + properties: { + id: endNode(r).id, + description: endNode(r).description + } + }, + relationship: { + type: type(r), + element_id: elementId(r) + } + } + ] AS entities """ CHAT_MODE_CONFIG_MAP= { From 00730d30163842338f1398003f7601f0704ff971 Mon Sep 17 00:00:00 2001 From: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Date: Fri, 20 Sep 2024 09:49:54 +0000 Subject: [PATCH 118/292] Commented youtube google api code --- backend/score.py | 2 ++ backend/src/main.py | 43 ++++++++++++++++++++++--------------------- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/backend/score.py b/backend/score.py index 227ff2901..63a26ec5b 100644 --- a/backend/score.py +++ b/backend/score.py @@ -121,6 +121,8 @@ async def create_source_knowledge_graph_url( except Exception as e: error_message = str(e) message = f" Unable to create source node for source type: {source_type} and source: {source}" + json_obj = {'error_message':error_message, 'status':'Failed','db_url':uri,'failed_count':1, 'source_type': source_type, 'source_url':source_url, 'wiki_query':wiki_query, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(json_obj, "ERROR") logging.exception(f'Exception Stack trace:') return create_api_response('Failed',message=message + error_message[:80],error=error_message,file_source=source_type) finally: diff --git a/backend/src/main.py b/backend/src/main.py index 49906aea8..4f2dc23d2 100644 --- a/backend/src/main.py +++ b/backend/src/main.py @@ -142,35 +142,36 @@ def create_source_node_graph_url_youtube(graph, model, source_url, source_type): obj_source_node.created_at = datetime.now() match = re.search(r'(?:v=)([0-9A-Za-z_-]{11})\s*',obj_source_node.url) logging.info(f"match value: {match}") - file_path = os.path.join(os.path.dirname(__file__),"llm-experiments_credentials.json") - logging.info(f'Credential file path {file_path}') - if os.path.exists(file_path): - logging.info("File path exist") - with open(file_path,'r') as file: - data = json.load(file) - logging.info(f"Project id : {data['project_id']}") - logging.info(f"Universal domain: {data['universe_domain']}") - else: - logging.warning("credntial file path not exist") + # file_path = os.path.join(os.path.dirname(__file__),"llm-experiments_credentials.json") + # logging.info(f'file path {file_path}') + + # if os.path.exists(file_path): + # logging.info("File path exist") + # with open(file_path,'r') as file: + # data = json.load(file) + # # logging.info(f"Project id : {data['project_id']}") + # # logging.info(f"Universal domain: {data['universe_domain']}") + # else: + # logging.warning("credntial file path not exist") video_id = parse_qs(urlparse(youtube_url).query).get('v') print(f'Video Id Youtube: {video_id}') - google_api_client = GoogleApiClient(service_account_path=Path(file_path)) - youtube_loader_channel = GoogleApiYoutubeLoader( - google_api_client=google_api_client, - video_ids=[video_id[0].strip()], add_video_info=True - ) - youtube_transcript = youtube_loader_channel.load() - page_content = youtube_transcript[0].page_content + # google_api_client = GoogleApiClient(service_account_path=Path(file_path)) + # youtube_loader_channel = GoogleApiYoutubeLoader( + # google_api_client=google_api_client, + # video_ids=[video_id[0].strip()], add_video_info=True + # ) + # youtube_transcript = youtube_loader_channel.load() + # page_content = youtube_transcript[0].page_content obj_source_node.file_name = match.group(1)#youtube_transcript[0].metadata["snippet"]["title"] - # transcript= get_youtube_combined_transcript(match.group(1)) - # print(transcript) - if page_content==None or len(page_content)==0: + transcript= get_youtube_combined_transcript(match.group(1)) + print(transcript) + if transcript==None or len(transcript)==0: message = f"Youtube transcript is not available for : {obj_source_node.file_name}" raise Exception(message) else: - obj_source_node.file_size = sys.getsizeof(page_content) + obj_source_node.file_size = sys.getsizeof(transcript) graphDb_data_Access = graphDBdataAccess(graph) graphDb_data_Access.create_source_node(obj_source_node) From 48c9f20052c5568a1e6d754f54b9ba2fc172e4d3 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Mon, 23 Sep 2024 08:51:56 +0000 Subject: [PATCH 119/292] added the error handling for passowrd decrypt error --- .../src/components/ChatBot/ChatInfoModal.tsx | 4 +-- .../src/components/ChatBot/ChatModeToggle.tsx | 6 ++-- frontend/src/components/UI/ErrroBoundary.tsx | 32 +++++++++++++------ frontend/src/utils/Constants.ts | 23 ++++++------- 4 files changed, 38 insertions(+), 27 deletions(-) diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index 53172256a..74823520a 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -176,7 +176,7 @@ const ChatInfoModal: React.FC = ({ ) : ( {mode != chatModeLables.graph ? Sources used : <>} - {mode != chatModeLables.graph ? Chunks : <>} + {mode != chatModeLables.graph ? Chunks : <>} {mode === chatModeLables.graph_vector || mode === chatModeLables.graph || mode === chatModeLables.graph_vector_fulltext || @@ -190,7 +190,7 @@ const ChatInfoModal: React.FC = ({ ) : ( <> )} - {mode === chatModeLables.entity_vector? Communities : <>} + {mode === chatModeLables.entity_vector ? Communities : <>} )} diff --git a/frontend/src/components/ChatBot/ChatModeToggle.tsx b/frontend/src/components/ChatBot/ChatModeToggle.tsx index 6c9bf459f..187c37178 100644 --- a/frontend/src/components/ChatBot/ChatModeToggle.tsx +++ b/frontend/src/components/ChatBot/ChatModeToggle.tsx @@ -8,7 +8,7 @@ import { capitalizeWithPlus } from '../../utils/Utils'; import { useCredentials } from '../../context/UserCredentials'; export default function ChatModeToggle({ menuAnchor, - closeHandler = () => { }, + closeHandler = () => {}, open, anchorPortal = true, disableBackdrop = false, @@ -38,7 +38,9 @@ export default function ChatModeToggle({ }, [isGdsActive, isCommunityAllowed]); const menuItems = useMemo(() => { return memoizedChatModes?.map((m) => { - const isDisabled = Boolean(selectedRows.length && !(m.mode === chatModeLables.vector || m.mode === chatModeLables.graph_vector)); + const isDisabled = Boolean( + selectedRows.length && !(m.mode === chatModeLables.vector || m.mode === chatModeLables.graph_vector) + ); const handleModeChange = () => { if (isDisabled) { setchatMode(chatModeLables.graph_vector); diff --git a/frontend/src/components/UI/ErrroBoundary.tsx b/frontend/src/components/UI/ErrroBoundary.tsx index b76a27695..b96337477 100644 --- a/frontend/src/components/UI/ErrroBoundary.tsx +++ b/frontend/src/components/UI/ErrroBoundary.tsx @@ -2,14 +2,14 @@ import React from 'react'; import { Banner } from '@neo4j-ndl/react'; export default class ErrorBoundary extends React.Component { - state = { hasError: false, errorMessage: '' }; + state = { hasError: false, errorMessage: '', errorName: '' }; static getDerivedStateFromError(_error: unknown) { return { hasError: true }; } componentDidCatch(error: Error, errorInfo: any) { - this.setState({ ...this.state, errorMessage: error.message }); + this.setState({ ...this.state, errorMessage: error.message, errorName: error.name }); console.log({ error }); console.log({ errorInfo }); } @@ -24,18 +24,32 @@ export default class ErrorBoundary extends React.Component { description={ this.state.errorMessage === 'Missing required parameter client_id.' ? 'Please Provide The Google Client ID For GCS Source' + : this.state.errorName === 'InvalidCharacterError' + ? 'Please Clear the Local Storage' : 'Sorry there was a problem loading this page' } title='Something went wrong' floating className='mt-8' - actions={[ - { - label: 'Documentation', - href: 'https://github.com/neo4j-labs/llm-graph-builder', - target: '_blank', - }, - ]} + actions={ + this.state.errorName === 'InvalidCharacterError' + ? [ + { + label: 'Clear local storage', + onClick: () => { + localStorage.clear(); + window.location.reload(); + }, + }, + ] + : [ + { + label: 'Documentation', + href: 'https://github.com/neo4j-labs/llm-graph-builder', + target: '_blank', + }, + ] + } >
    ); diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index 0b2f60cba..e249d94d4 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -67,14 +67,14 @@ export const defaultLLM = llms?.includes('openai-gpt-4o') export const chatModeLables = { vector: 'vector', - graph : 'graph', + graph: 'graph', graph_vector: 'graph+vector', fulltext: 'fulltext', graph_vector_fulltext: 'graph+vector+fulltext', - entity_vector:'entity search+vector', + entity_vector: 'entity search+vector', unavailableChatMode: 'Chat mode is unavailable when rows are selected', - selected:'Selected' -} + selected: 'Selected', +}; export const chatModes = process.env?.VITE_CHAT_MODES?.trim() != '' ? process.env.VITE_CHAT_MODES?.split(',').map((mode) => ({ @@ -88,28 +88,23 @@ export const chatModes = }, { mode: chatModeLables.graph, - description: - 'Translates text to Cypher queries for precise data retrieval from a graph database.' + description: 'Translates text to Cypher queries for precise data retrieval from a graph database.', }, { mode: chatModeLables.graph_vector, - description: - 'Combines vector indexing and graph connections for contextually enhanced semantic search.', + description: 'Combines vector indexing and graph connections for contextually enhanced semantic search.', }, { mode: chatModeLables.fulltext, - description: - 'Conducts fast, keyword-based search using full-text indexing on text chunks.', + description: 'Conducts fast, keyword-based search using full-text indexing on text chunks.', }, { mode: chatModeLables.graph_vector_fulltext, - description: - 'Integrates vector, graph, and full-text indexing for comprehensive search results.', + description: 'Integrates vector, graph, and full-text indexing for comprehensive search results.', }, { mode: chatModeLables.entity_vector, - description: - 'Uses vector indexing on entity nodes for highly relevant entity-based search.', + description: 'Uses vector indexing on entity nodes for highly relevant entity-based search.', }, ]; From 9d89cb2bf829c67636d1db961412f200897b8657 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Tue, 24 Sep 2024 06:47:57 +0000 Subject: [PATCH 120/292] wordings changes --- frontend/src/components/UI/ErrroBoundary.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/UI/ErrroBoundary.tsx b/frontend/src/components/UI/ErrroBoundary.tsx index b96337477..4d296b488 100644 --- a/frontend/src/components/UI/ErrroBoundary.tsx +++ b/frontend/src/components/UI/ErrroBoundary.tsx @@ -25,7 +25,7 @@ export default class ErrorBoundary extends React.Component { this.state.errorMessage === 'Missing required parameter client_id.' ? 'Please Provide The Google Client ID For GCS Source' : this.state.errorName === 'InvalidCharacterError' - ? 'Please Clear the Local Storage' + ? "We've updated our security measures. To ensure smooth access, please clear your local storage" : 'Sorry there was a problem loading this page' } title='Something went wrong' @@ -35,7 +35,7 @@ export default class ErrorBoundary extends React.Component { this.state.errorName === 'InvalidCharacterError' ? [ { - label: 'Clear local storage', + label: 'Clear Storage', onClick: () => { localStorage.clear(); window.location.reload(); From 69109f9fdf22120b8e96e38694c41da1ed1c84a2 Mon Sep 17 00:00:00 2001 From: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Date: Tue, 24 Sep 2024 10:47:13 +0000 Subject: [PATCH 121/292] Exclude default labels from get_labels_and_relationtypes --- backend/src/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/main.py b/backend/src/main.py index 4f2dc23d2..07773d3d1 100644 --- a/backend/src/main.py +++ b/backend/src/main.py @@ -590,11 +590,11 @@ def get_labels_and_relationtypes(graph): query = """ RETURN collect { CALL db.labels() yield label - WHERE NOT label IN ['Chunk','_Bloom_Perspective_'] + WHERE NOT label IN ['Chunk','_Bloom_Perspective_', '__Community__', '__Entity__'] return label order by label limit 100 } as labels, collect { CALL db.relationshipTypes() yield relationshipType as type - WHERE NOT type IN ['PART_OF', 'NEXT_CHUNK', 'HAS_ENTITY', '_Bloom_Perspective_'] + WHERE NOT type IN ['PART_OF', 'NEXT_CHUNK', 'HAS_ENTITY', '_Bloom_Perspective_','FIRST_CHUNK'] return type order by type LIMIT 100 } as relationshipTypes """ graphDb_data_Access = graphDBdataAccess(graph) From d41a9209113e8187deb06c5f821da686da05bdaf Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Tue, 24 Sep 2024 18:13:19 +0530 Subject: [PATCH 122/292] Post-Processing-Alerts (#758) * added the alerts before and after the post processing * Tooltip changes --- frontend/src/components/ChatBot/Chatbot.tsx | 17 ++++++++++++++--- frontend/src/components/Content.tsx | 6 +++++- .../Popups/Settings/SchemaFromText.tsx | 2 +- frontend/src/utils/Constants.ts | 14 +++++++------- 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/frontend/src/components/ChatBot/Chatbot.tsx b/frontend/src/components/ChatBot/Chatbot.tsx index 412f485ed..25cb944d3 100644 --- a/frontend/src/components/ChatBot/Chatbot.tsx +++ b/frontend/src/components/ChatBot/Chatbot.tsx @@ -19,6 +19,8 @@ import { buttonCaptions, chatModeLables, tooltips } from '../../utils/Constants' import useSpeechSynthesis from '../../hooks/useSpeech'; import ButtonWithToolTip from '../UI/ButtonWithToolTip'; import FallBackDialog from '../UI/FallBackDialog'; +import { capitalizeWithPlus } from '../../utils/Utils'; +import { capitalize } from '@mui/material'; const InfoModal = lazy(() => import('./ChatInfoModal')); const Chatbot: FC = (props) => { @@ -44,7 +46,7 @@ const Chatbot: FC = (props) => { const [tokensUsed, setTokensUsed] = useState(0); const [cypherQuery, setcypherQuery] = useState(''); const [copyMessageId, setCopyMessageId] = useState(null); - const [chatsMode, setChatsMode] = useState(chatModeLables.graph_vector); + const [chatsMode, setChatsMode] = useState(chatModeLables.graph_vector_fulltext); const [graphEntitites, setgraphEntitites] = useState<[]>([]); const [messageError, setmessageError] = useState(''); @@ -179,7 +181,7 @@ const Chatbot: FC = (props) => { let error; let entitiysearchonly_entities; const datetime = `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`; - const userMessage = { id: Date.now(), user: 'user', message: inputMessage, datetime: datetime }; + const userMessage = { id: Date.now(), user: 'user', message: inputMessage, datetime: datetime, mode: chatMode }; setListMessages([...listMessages, userMessage]); try { setInputMessage(''); @@ -325,6 +327,15 @@ const Chatbot: FC = (props) => { className={`p-4 self-start ${isFullScreen ? 'max-w-[55%]' : ''} ${ chat.user === 'chatbot' ? 'n-bg-palette-neutral-bg-strong' : 'n-bg-palette-primary-bg-weak' } `} + subheader={ + chat.user !== 'chatbot' && chat.mode?.length ? ( + + Chat Mode: {chat.mode.includes('+') ? capitalizeWithPlus(chat.mode) : capitalize(chat.mode)} + + ) : ( + '' + ) + } >
    = (props) => { = ({ } if (processedCount === 1 && queue.isEmpty()) { (async () => { + showNormalToast('Some Q&A functionality will only be available afterwards.'); await postProcessing(userCredentials as UserCredentials, postProcessingTasks); + showSuccessToast('All Q&A functionality is available now.'); })(); } }, [processedCount, userCredentials, queue]); @@ -374,7 +376,9 @@ const Content: React.FC = ({ const addFilesToQueue = async (remainingFiles: CustomFile[]) => { if (!remainingFiles.length) { + showNormalToast('Some Q&A functionality will only be available afterwards.'); await postProcessing(userCredentials as UserCredentials, postProcessingTasks); + showSuccessToast('All Q&A functionality is available now.'); } for (let index = 0; index < remainingFiles.length; index++) { const f = remainingFiles[index]; @@ -787,7 +791,7 @@ const Content: React.FC = ({
    Date: Wed, 25 Sep 2024 12:36:26 +0000 Subject: [PATCH 123/292] added write access check --- backend/score.py | 6 +++-- backend/src/QA_integration.py | 10 ++++----- backend/src/graphDB_dataAccess.py | 37 ++++++++++++++++++++++++++----- backend/src/main.py | 4 ++-- 4 files changed, 43 insertions(+), 14 deletions(-) diff --git a/backend/score.py b/backend/score.py index e47905363..a17e93772 100644 --- a/backend/score.py +++ b/backend/score.py @@ -296,7 +296,9 @@ async def chat_bot(uri=Form(),model=Form(None),userName=Form(), password=Form(), graph = Neo4jGraph( url=uri,username=userName,password=password,database=database,sanitize = True, refresh_schema=True) else: graph = create_graph_database_connection(uri, userName, password, database) - result = await asyncio.to_thread(QA_RAG,graph=graph,model=model,question=question,document_names=document_names,session_id=session_id,mode=mode) + graph_DB_dataAccess = graphDBdataAccess(graph) + write_access = graph_DB_dataAccess.check_account_access(database=database) + result = await asyncio.to_thread(QA_RAG,graph=graph,model=model,question=question,document_names=document_names,session_id=session_id,mode=mode,write_access) total_call_time = time.time() - qa_rag_start_time logging.info(f"Total Response time is {total_call_time:.2f} seconds") @@ -382,7 +384,7 @@ async def clear_chat_bot(uri=Form(),userName=Form(), password=Form(), database=F async def connect(uri=Form(), userName=Form(), password=Form(), database=Form()): try: graph = create_graph_database_connection(uri, userName, password, database) - result = await asyncio.to_thread(connection_check_and_get_vector_dimensions, graph) + result = await asyncio.to_thread(connection_check_and_get_vector_dimensions, graph, database) json_obj = {'api_name':'connect','db_url':uri,'status':result, 'count':1, 'logging_time': formatted_time(datetime.now(timezone.utc))} logger.log_struct(json_obj, "INFO") return create_api_response('Success',data=result) diff --git a/backend/src/QA_integration.py b/backend/src/QA_integration.py index eb6ac5be1..3849c8e29 100644 --- a/backend/src/QA_integration.py +++ b/backend/src/QA_integration.py @@ -34,7 +34,7 @@ from src.llm import get_llm from src.shared.common_fn import load_embedding_model from src.shared.constants import * - +from src.graphDB_dataAccess import graphDBdataAccess load_dotenv() EMBEDDING_MODEL = os.getenv('EMBEDDING_MODEL') @@ -560,13 +560,13 @@ def process_graph_response(model, graph, question, messages, history): "user": "chatbot" } -def create_neo4j_chat_message_history(graph, session_id, local=False): +def create_neo4j_chat_message_history(graph, session_id, write_access=True): """ Creates and returns a Neo4jChatMessageHistory instance. """ try: - if not local: + if write_access: history = Neo4jChatMessageHistory( graph=graph, session_id=session_id @@ -594,10 +594,10 @@ def get_chat_mode_settings(mode,settings_map=CHAT_MODE_CONFIG_MAP): return chat_mode_settings -def QA_RAG(graph, model, question, document_names, session_id, mode): +def QA_RAG(graph,model, question, document_names, session_id, mode, write_access=True): logging.info(f"Chat Mode: {mode}") - history = create_neo4j_chat_message_history(graph, session_id) + history = create_neo4j_chat_message_history(graph, session_id, write_access) messages = history.messages user_question = HumanMessage(content=question) diff --git a/backend/src/graphDB_dataAccess.py b/backend/src/graphDB_dataAccess.py index 279451bdf..406063074 100644 --- a/backend/src/graphDB_dataAccess.py +++ b/backend/src/graphDB_dataAccess.py @@ -141,6 +141,32 @@ def update_KNN_graph(self): else: logging.info("Vector index does not exist, So KNN graph not update") + def check_account_access(self, database): + query = """ + SHOW USER PRIVILEGES + YIELD * + WHERE graph = $database AND action IN ['read', 'write'] + RETURN COUNT(*) AS readAccessCount + """ + try: + logging.info(f"Checking access for database: {database}") + + result = self.graph.query(query, params={"database": database}) + read_access_count = result[0]["readAccessCount"] if result else 0 + + logging.info(f"Read access count: {read_access_count}") + + if read_access_count > 0: + logging.info("The account has read access.") + return False + else: + logging.info("The account has write access.") + return True + + except Exception as e: + logging.error(f"Error checking account access: {e}") + return False + def check_gds_version(self): try: gds_procedure_count = """ @@ -162,7 +188,7 @@ def check_gds_version(self): logging.error(f"An error occurred while checking GDS version: {e}") return False - def connection_check_and_get_vector_dimensions(self): + def connection_check_and_get_vector_dimensions(self,database): """ Get the vector index dimension from database and application configuration and DB connection status @@ -189,18 +215,19 @@ def connection_check_and_get_vector_dimensions(self): logging.info(f'embedding model:{embeddings} and dimesion:{application_dimension}') gds_status = self.check_gds_version() + write_access = self.check_account_access(database=database) if self.graph: if len(db_vector_dimension) > 0: - return {'db_vector_dimension': db_vector_dimension[0]['vector_dimensions'], 'application_dimension':application_dimension, 'message':"Connection Successful","gds_status":gds_status} + return {'db_vector_dimension': db_vector_dimension[0]['vector_dimensions'], 'application_dimension':application_dimension, 'message':"Connection Successful","gds_status":gds_status,"write_access":write_access} else: if len(db_vector_dimension) == 0 and len(result_chunks) == 0: logging.info("Chunks and vector index does not exists in database") - return {'db_vector_dimension': 0, 'application_dimension':application_dimension, 'message':"Connection Successful","chunks_exists":False,"gds_status":gds_status} + return {'db_vector_dimension': 0, 'application_dimension':application_dimension, 'message':"Connection Successful","chunks_exists":False,"gds_status":gds_status,"write_access":write_access} elif len(db_vector_dimension) == 0 and result_chunks[0]['hasEmbedding']==0 and result_chunks[0]['chunks'] > 0: - return {'db_vector_dimension': 0, 'application_dimension':application_dimension, 'message':"Connection Successful","chunks_exists":True,"gds_status":gds_status} + return {'db_vector_dimension': 0, 'application_dimension':application_dimension, 'message':"Connection Successful","chunks_exists":True,"gds_status":gds_status,"write_access":write_access} else: - return {'message':"Connection Successful","gds_status":gds_status} + return {'message':"Connection Successful","gds_status": gds_status,"write_access":write_access} def execute_query(self, query, param=None): return self.graph.query(query, param) diff --git a/backend/src/main.py b/backend/src/main.py index 588df22ed..c452be8f8 100644 --- a/backend/src/main.py +++ b/backend/src/main.py @@ -502,7 +502,7 @@ def update_graph(graph): graph_DB_dataAccess.update_KNN_graph() -def connection_check_and_get_vector_dimensions(graph): +def connection_check_and_get_vector_dimensions(graph,database): """ Args: uri: URI of the graph to extract @@ -513,7 +513,7 @@ def connection_check_and_get_vector_dimensions(graph): Returns a status of connection from NEO4j is success or failure """ graph_DB_dataAccess = graphDBdataAccess(graph) - return graph_DB_dataAccess.connection_check_and_get_vector_dimensions() + return graph_DB_dataAccess.connection_check_and_get_vector_dimensions(database) def merge_chunks_local(file_name, total_chunks, chunk_dir, merged_dir): From 91a4d30ddcb89042f5a54a883d56bfa2a6746bb7 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Wed, 25 Sep 2024 12:37:46 +0000 Subject: [PATCH 124/292] added write access param --- backend/score.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/score.py b/backend/score.py index a17e93772..b8573fb2f 100644 --- a/backend/score.py +++ b/backend/score.py @@ -298,7 +298,7 @@ async def chat_bot(uri=Form(),model=Form(None),userName=Form(), password=Form(), graph = create_graph_database_connection(uri, userName, password, database) graph_DB_dataAccess = graphDBdataAccess(graph) write_access = graph_DB_dataAccess.check_account_access(database=database) - result = await asyncio.to_thread(QA_RAG,graph=graph,model=model,question=question,document_names=document_names,session_id=session_id,mode=mode,write_access) + result = await asyncio.to_thread(QA_RAG,graph=graph,model=model,question=question,document_names=document_names,session_id=session_id,mode=mode,write_access=write_access) total_call_time = time.time() - qa_rag_start_time logging.info(f"Total Response time is {total_call_time:.2f} seconds") From 2ab06d6eaeba6a37ec048a8364ea329519c6ebe8 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Wed, 25 Sep 2024 14:30:06 +0000 Subject: [PATCH 125/292] added fulltext creation --- backend/score.py | 7 +++-- backend/src/post_processing.py | 55 ++++++++++++++++++++++++---------- 2 files changed, 43 insertions(+), 19 deletions(-) diff --git a/backend/score.py b/backend/score.py index b8573fb2f..b5f0ea23d 100644 --- a/backend/score.py +++ b/backend/score.py @@ -14,7 +14,7 @@ from src.graphDB_dataAccess import graphDBdataAccess from src.graph_query import get_graph_results from src.chunkid_entities import get_entities_from_chunkids -from src.post_processing import create_fulltext, create_entity_embedding +from src.post_processing import create_fulltext_indexes, create_entity_embedding from sse_starlette.sse import EventSourceResponse from src.communities import create_communities import json @@ -261,14 +261,15 @@ async def post_processing(uri=Form(), userName=Form(), password=Form(), database logging.info(f'Updated KNN Graph') if "enable_hybrid_search_and_fulltext_search_in_bloom" in tasks: - await asyncio.to_thread(create_fulltext, uri=uri, username=userName, password=password, database=database,type="entities") - # await asyncio.to_thread(create_fulltext, uri=uri, username=userName, password=password, database=database,type="keyword") + await asyncio.to_thread(create_fulltext_indexes, uri=uri, username=userName, password=password, database=database) json_obj = {'api_name': 'post_processing/enable_hybrid_search_and_fulltext_search_in_bloom', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} logging.info(f'Full Text index created') + if os.environ.get('ENTITY_EMBEDDING','False').upper()=="TRUE" and "materialize_entity_similarities" in tasks: await asyncio.to_thread(create_entity_embedding, graph) json_obj = {'api_name': 'post_processing/create_entity_embedding', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} logging.info(f'Entity Embeddings created') + if "create_communities" in tasks: model = "openai-gpt-4o" await asyncio.to_thread(create_communities, uri, userName, password, database,model) diff --git a/backend/src/post_processing.py b/backend/src/post_processing.py index 7d038c61b..88d99385a 100644 --- a/backend/src/post_processing.py +++ b/backend/src/post_processing.py @@ -10,30 +10,26 @@ FULL_TEXT_QUERY = "CREATE FULLTEXT INDEX entities FOR (n{labels_str}) ON EACH [n.id, n.description];" FILTER_LABELS = ["Chunk","Document","__Community__"] - HYBRID_SEARCH_INDEX_DROP_QUERY = "DROP INDEX keyword IF EXISTS;" -HYBRID_SEARCH_FULL_TEXT_QUERY = "CREATE FULLTEXT INDEX keyword FOR (n:Chunk) ON EACH [n.text]" +HYBRID_SEARCH_FULL_TEXT_QUERY = "CREATE FULLTEXT INDEX keyword FOR (n:Chunk) ON EACH [n.text]" -def create_fulltext(uri, username, password, database,type): - start_time = time.time() - logging.info("Starting the process of creating a full-text index.") +COMMUNITY_INDEX_DROP_QUERY = "DROP INDEX community_keyword IF EXISTS;" +COMMUNITY_INDEX_FULL_TEXT_QUERY = "CREATE FULLTEXT INDEX community_keyword FOR (n:`__Community__`) ON EACH [n.summary]" - try: - driver = GraphDatabase.driver(uri, auth=(username, password), database=database) - driver.verify_connectivity() - logging.info("Database connectivity verified.") - except Exception as e: - logging.error(f"Failed to create a database driver or verify connectivity: {e}") - return +def create_fulltext(driver,type): + + start_time = time.time() try: with driver.session() as session: try: start_step = time.time() if type == "entities": drop_query = DROP_INDEX_QUERY - else: + elif type == "hybrid": drop_query = HYBRID_SEARCH_INDEX_DROP_QUERY + else: + drop_query = COMMUNITY_INDEX_DROP_QUERY session.run(drop_query) logging.info(f"Dropped existing index (if any) in {time.time() - start_step:.2f} seconds.") except Exception as e: @@ -58,8 +54,11 @@ def create_fulltext(uri, username, password, database,type): start_step = time.time() if type == "entities": fulltext_query = FULL_TEXT_QUERY.format(labels_str=labels_str) - else: + elif type == "hybrid": fulltext_query = HYBRID_SEARCH_FULL_TEXT_QUERY + else: + fulltext_query = COMMUNITY_INDEX_FULL_TEXT_QUERY + session.run(fulltext_query) logging.info(f"Created full-text index in {time.time() - start_step:.2f} seconds.") except Exception as e: @@ -68,10 +67,34 @@ def create_fulltext(uri, username, password, database,type): except Exception as e: logging.error(f"An error occurred during the session: {e}") finally: - driver.close() - logging.info("Driver closed.") logging.info(f"Process completed in {time.time() - start_time:.2f} seconds.") + +def create_fulltext_indexes(uri, username, password, database): + types = ["entities", "hybrid", "community"] + logging.info("Starting the process of creating full-text indexes.") + + try: + driver = GraphDatabase.driver(uri, auth=(username, password), database=database) + driver.verify_connectivity() + logging.info("Database connectivity verified.") + except Exception as e: + logging.error(f"An unexpected error occurred: {e}") + return + + for index_type in types: + try: + logging.info(f"Creating a full-text index for type '{index_type}'.") + create_fulltext(driver, index_type) + logging.info(f"Full-text index for type '{index_type}' created successfully.") + except Exception as e: + logging.error(f"Failed to create full-text index for type '{index_type}': {e}") + + logging.info("Full-text indexes creation process completed.") + driver.close() + logging.info("Driver closed.") + + def create_entity_embedding(graph:Neo4jGraph): rows = fetch_entities_for_embedding(graph) for i in range(0, len(rows), 1000): From 9414f31b82882f5781eba539e459fcbc84227245 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Thu, 26 Sep 2024 07:23:07 +0000 Subject: [PATCH 126/292] disabled the write and delete actions for read only user mode --- frontend/src/components/Content.tsx | 21 +- .../src/components/Layout/DrawerDropzone.tsx | 284 ++++++++++-------- frontend/src/components/Layout/PageLayout.tsx | 3 +- frontend/src/components/Layout/SideNav.tsx | 10 +- .../ConnectionModal/ConnectionModal.tsx | 6 +- frontend/src/context/UserCredentials.tsx | 5 + frontend/src/types.ts | 2 + 7 files changed, 190 insertions(+), 141 deletions(-) diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 517ada241..92a5e2b76 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -59,8 +59,16 @@ const Content: React.FC = ({ }); const [openGraphView, setOpenGraphView] = useState(false); const [inspectedName, setInspectedName] = useState(''); - const { setUserCredentials, userCredentials, connectionStatus, setConnectionStatus, isGdsActive, setGdsActive } = - useCredentials(); + const { + setUserCredentials, + userCredentials, + connectionStatus, + setConnectionStatus, + isGdsActive, + setGdsActive, + setIsReadOnlyUser, + isReadOnlyUser, + } = useCredentials(); const [showConfirmationModal, setshowConfirmationModal] = useState(false); const [extractLoading, setextractLoading] = useState(false); const [retryFile, setRetryFile] = useState(''); @@ -118,6 +126,9 @@ const Content: React.FC = ({ if (neo4jConnection.isgdsActive !== undefined) { setGdsActive(neo4jConnection.isgdsActive); } + if (neo4jConnection.isReadOnlyUser !== undefined) { + setIsReadOnlyUser(neo4jConnection.isReadOnlyUser); + } } else { setOpenConnection((prev) => ({ ...prev, openPopUp: true })); } @@ -756,7 +767,7 @@ const Content: React.FC = ({ />
    - Neo4j connection + Neo4j connection {isReadOnlyUser ? '(Read only Mode)' : ''} = ({ label='Graph Enhancemnet Settings' className='mr-2.5' onClick={toggleEnhancementDialog} - disabled={!connectionStatus} + disabled={!connectionStatus || isReadOnlyUser} size={isTablet ? 'small' : 'medium'} > Graph Enhancement @@ -883,7 +894,7 @@ const Content: React.FC = ({ } placement='top' onClick={() => setshowDeletePopUp(true)} - disabled={!selectedfileslength} + disabled={!selectedfileslength||isReadOnlyUser} className='ml-0.5' label='Delete Files' size={isTablet ? 'small' : 'medium'} diff --git a/frontend/src/components/Layout/DrawerDropzone.tsx b/frontend/src/components/Layout/DrawerDropzone.tsx index f423f62f9..07d91f642 100644 --- a/frontend/src/components/Layout/DrawerDropzone.tsx +++ b/frontend/src/components/Layout/DrawerDropzone.tsx @@ -11,6 +11,7 @@ import { APP_SOURCES } from '../../utils/Constants'; import GenericButton from '../WebSources/GenericSourceButton'; import GenericModal from '../WebSources/GenericSourceModal'; import FallBackDialog from '../UI/FallBackDialog'; +import { useCredentials } from '../../context/UserCredentials'; const S3Modal = lazy(() => import('../DataSources/AWS/S3Modal')); const GCSModal = lazy(() => import('../DataSources/GCS/GCSModal')); @@ -25,6 +26,7 @@ const DrawerDropzone: React.FC = ({ }) => { const [isBackendConnected, setIsBackendConnected] = useState(false); const { closeAlert, alertState } = useAlertContext(); + const { isReadOnlyUser } = useCredentials(); useEffect(() => { async function getHealthStatus() { @@ -54,143 +56,167 @@ const DrawerDropzone: React.FC = ({ return (
    - - {alertState.showAlert && ( - - )} -
    -
    -
    -
    - {process.env.VITE_ENV != 'PROD' && ( - - - {!isBackendConnected ? : } + {!isReadOnlyUser ? ( + + {alertState.showAlert && ( + + )} +
    +
    +
    +
    + {process.env.VITE_ENV != 'PROD' && ( + + + {!isBackendConnected ? : } + + Backend connection status - Backend connection status - - )} -
    - {process.env.VITE_ENV != 'PROD' ? ( - <> - - {APP_SOURCES != undefined && APP_SOURCES.includes('local') && ( -
    - -
    - )} - {(APP_SOURCES != undefined && APP_SOURCES.includes('s3')) || - (APP_SOURCES != undefined && APP_SOURCES.includes('gcs')) ? ( - <> - {(APP_SOURCES.includes('youtube') || - APP_SOURCES.includes('wiki') || - APP_SOURCES.includes('web')) && ( -
    - - -
    - )} - {APP_SOURCES.includes('s3') && ( -
    - - }> - - -
    - )} - {APP_SOURCES.includes('gcs') && ( -
    - - }> + )} +
    + {process.env.VITE_ENV != 'PROD' ? ( + <> + + {APP_SOURCES != undefined && APP_SOURCES.includes('local') && ( +
    + +
    + )} + {(APP_SOURCES != undefined && APP_SOURCES.includes('s3')) || + (APP_SOURCES != undefined && APP_SOURCES.includes('gcs')) ? ( + <> + {(APP_SOURCES.includes('youtube') || + APP_SOURCES.includes('wiki') || + APP_SOURCES.includes('web')) && ( +
    + + +
    + )} + {APP_SOURCES.includes('s3') && ( +
    + + }> + + +
    + )} + {APP_SOURCES.includes('gcs') && ( +
    + + }> + + +
    + )} + + ) : ( + <> + )} +
    + + ) : ( + <> + + {APP_SOURCES != undefined && APP_SOURCES.includes('local') && ( +
    + +
    + )} + {((APP_SOURCES != undefined && APP_SOURCES.includes('youtube')) || + (APP_SOURCES != undefined && APP_SOURCES.includes('wiki')) || + (APP_SOURCES != undefined && APP_SOURCES.includes('web'))) && ( +
    + + +
    + )} + {(APP_SOURCES != undefined && APP_SOURCES.includes('s3')) || + (APP_SOURCES != undefined && APP_SOURCES.includes('gcs')) ? ( + <> + {APP_SOURCES != undefined && APP_SOURCES.includes('s3') && ( +
    + + }> + + +
    + )} + {APP_SOURCES != undefined && APP_SOURCES.includes('gcs') && ( +
    + - -
    - )} - - ) : ( - <> - )} -
    - - ) : ( - <> - - {APP_SOURCES != undefined && APP_SOURCES.includes('local') && ( -
    - -
    - )} - {((APP_SOURCES != undefined && APP_SOURCES.includes('youtube')) || - (APP_SOURCES != undefined && APP_SOURCES.includes('wiki')) || - (APP_SOURCES != undefined && APP_SOURCES.includes('web'))) && ( -
    - - -
    - )} - {(APP_SOURCES != undefined && APP_SOURCES.includes('s3')) || - (APP_SOURCES != undefined && APP_SOURCES.includes('gcs')) ? ( - <> - {APP_SOURCES != undefined && APP_SOURCES.includes('s3') && ( -
    - - }> - - -
    - )} - {APP_SOURCES != undefined && APP_SOURCES.includes('gcs') && ( -
    - - -
    - )} - - ) : ( - <> - )} -
    - - )} +
    + )} + + ) : ( + <> + )} + + + )} +
    -
    - + + ) : ( + + + This user account does not have permission to access or manage data sources. + + + )}
    ); diff --git a/frontend/src/components/Layout/PageLayout.tsx b/frontend/src/components/Layout/PageLayout.tsx index c2c21116c..07d795484 100644 --- a/frontend/src/components/Layout/PageLayout.tsx +++ b/frontend/src/components/Layout/PageLayout.tsx @@ -22,6 +22,7 @@ export default function PageLayoutNew({ openSettingsDialog: () => void; }) { const largedesktops = useMediaQuery(`(min-width:1440px )`); + const { userCredentials, connectionStatus } = useCredentials(); const [isLeftExpanded, setIsLeftExpanded] = useState(Boolean(largedesktops)); const [isRightExpanded, setIsRightExpanded] = useState(Boolean(largedesktops)); const [showChatBot, setShowChatBot] = useState(false); @@ -31,7 +32,7 @@ export default function PageLayoutNew({ const [shows3Modal, toggleS3Modal] = useReducer((s) => !s, false); const [showGCSModal, toggleGCSModal] = useReducer((s) => !s, false); const [showGenericModal, toggleGenericModal] = useReducer((s) => !s, false); - const { userCredentials, connectionStatus } = useCredentials(); + const toggleLeftDrawer = () => { if (largedesktops) { setIsLeftExpanded(!isLeftExpanded); diff --git a/frontend/src/components/Layout/SideNav.tsx b/frontend/src/components/Layout/SideNav.tsx index bdc43c8be..ee3ef510b 100644 --- a/frontend/src/components/Layout/SideNav.tsx +++ b/frontend/src/components/Layout/SideNav.tsx @@ -44,7 +44,7 @@ const SideNav: React.FC = ({ const [chatModeAnchor, setchatModeAnchor] = useState(null); const [showChatMode, setshowChatMode] = useState(false); const largedesktops = useMediaQuery(`(min-width:1440px )`); - const { connectionStatus } = useCredentials(); + const { connectionStatus, isReadOnlyUser } = useCredentials(); const date = new Date(); useEffect(() => { @@ -125,7 +125,7 @@ const SideNav: React.FC = ({ /> )} - {!largedesktops && position === 'left' && ( + {!largedesktops && position === 'left' && !isReadOnlyUser && ( @@ -137,7 +137,7 @@ const SideNav: React.FC = ({ } /> )} - {!largedesktops && APP_SOURCES.includes('gcs') && position === 'left' && ( + {!largedesktops && APP_SOURCES.includes('gcs') && position === 'left' && !isReadOnlyUser && ( @@ -149,7 +149,7 @@ const SideNav: React.FC = ({ } /> )} - {!largedesktops && APP_SOURCES.includes('s3') && position === 'left' && ( + {!largedesktops && APP_SOURCES.includes('s3') && position === 'left' && !isReadOnlyUser && ( @@ -161,7 +161,7 @@ const SideNav: React.FC = ({ } /> )} - {!largedesktops && APP_SOURCES.includes('web') && position === 'left' && ( + {!largedesktops && APP_SOURCES.includes('web') && position === 'left' && !isReadOnlyUser && ( diff --git a/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx b/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx index 0213e9502..618cc7b80 100644 --- a/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx +++ b/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx @@ -41,7 +41,7 @@ export default function ConnectionModal({ const [username, setUsername] = useState(initialusername ?? 'neo4j'); const [password, setPassword] = useState(''); const [connectionMessage, setMessage] = useState({ type: 'unknown', content: '' }); - const { setUserCredentials, userCredentials, setGdsActive } = useCredentials(); + const { setUserCredentials, userCredentials, setGdsActive, setIsReadOnlyUser } = useCredentials(); const [isLoading, setIsLoading] = useState(false); const [searchParams, setSearchParams] = useSearchParams(); const [userDbVectorIndex, setUserDbVectorIndex] = useState(initialuserdbvectorindex ?? undefined); @@ -208,7 +208,10 @@ export default function ConnectionModal({ throw new Error(response.data.error); } else { const isgdsActive = response.data.data.gds_status; + const isReadOnlyUser = !response.data.data.write_access; setGdsActive(isgdsActive); + console.log({ isReadOnlyUser }); + setIsReadOnlyUser(isReadOnlyUser); localStorage.setItem( 'neo4j.connection', JSON.stringify({ @@ -218,6 +221,7 @@ export default function ConnectionModal({ database: database, userDbVectorIndex, isgdsActive, + isReadOnlyUser, }) ); setUserDbVectorIndex(response.data.data.db_vector_dimension); diff --git a/frontend/src/context/UserCredentials.tsx b/frontend/src/context/UserCredentials.tsx index 1b5eda2da..cd3db2d62 100644 --- a/frontend/src/context/UserCredentials.tsx +++ b/frontend/src/context/UserCredentials.tsx @@ -12,6 +12,8 @@ export const UserConnection = createContext({ setGdsActive: () => false, connectionStatus: false, setConnectionStatus: () => null, + isReadOnlyUser: false, + setIsReadOnlyUser: () => null, }); export const useCredentials = () => { const userCredentials = useContext(UserConnection); @@ -20,6 +22,7 @@ export const useCredentials = () => { const UserCredentialsWrapper: FunctionComponent = (props) => { const [userCredentials, setUserCredentials] = useState(null); const [isGdsActive, setGdsActive] = useState(false); + const [isReadOnlyUser, setIsReadOnlyUser] = useState(false); const [connectionStatus, setConnectionStatus] = useReducer((state) => !state, false); const value = { userCredentials, @@ -28,6 +31,8 @@ const UserCredentialsWrapper: FunctionComponent = (props) => { setGdsActive, connectionStatus, setConnectionStatus, + isReadOnlyUser, + setIsReadOnlyUser, }; return {props.children}; diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 9631335a9..10f16e4d6 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -631,6 +631,8 @@ export interface ContextProps { setUserCredentials: (UserCredentials: UserCredentials) => void; isGdsActive: boolean; setGdsActive: Dispatch>; + isReadOnlyUser: boolean; + setIsReadOnlyUser: Dispatch>; connectionStatus: boolean; setConnectionStatus: Dispatch>; } From f116300741a72f9698e7a894dcc25642c5be7844 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Thu, 26 Sep 2024 08:32:47 +0000 Subject: [PATCH 127/292] modified query --- backend/src/graphDB_dataAccess.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphDB_dataAccess.py b/backend/src/graphDB_dataAccess.py index f4a569d8b..c2e2f6424 100644 --- a/backend/src/graphDB_dataAccess.py +++ b/backend/src/graphDB_dataAccess.py @@ -148,7 +148,7 @@ def check_account_access(self, database): query = """ SHOW USER PRIVILEGES YIELD * - WHERE graph = $database AND action IN ['read', 'write'] + WHERE graph = $database AND action IN ['read'] RETURN COUNT(*) AS readAccessCount """ try: From dbb77d6e822dc8075234db94bda212c8920e347c Mon Sep 17 00:00:00 2001 From: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Date: Mon, 23 Sep 2024 09:06:28 +0000 Subject: [PATCH 128/292] test updates --- backend/test_commutiesqa.py | 244 ++++++++++++++++++++++++++++++++++ backend/test_integrationqa.py | 3 +- 2 files changed, 245 insertions(+), 2 deletions(-) create mode 100644 backend/test_commutiesqa.py diff --git a/backend/test_commutiesqa.py b/backend/test_commutiesqa.py new file mode 100644 index 000000000..771cb044c --- /dev/null +++ b/backend/test_commutiesqa.py @@ -0,0 +1,244 @@ +import json +import os +import shutil +import logging +import pandas as pd +from datetime import datetime as dt +from dotenv import load_dotenv +from score import * +from src.main import * +from src.QA_integration import QA_RAG +from langserve import add_routes +from graphdatascience import GraphDataScience +from src.entities.source_node import sourceNode + +# Load environment variables if needed +load_dotenv() +# Constants +URI = '' +USERNAME = '' +PASSWORD = '' +DATABASE = 'persistent1' +CHUNK_DIR = os.path.join(os.path.dirname(__file__), "chunks") +MERGED_DIR = os.path.join(os.path.dirname(__file__), "merged_files") + +# Initialize database connection +graph = create_graph_database_connection(URI, USERNAME, PASSWORD, DATABASE) + +def create_source_node_local(graph, model, file_name): + """Creates a source node for a local file.""" + source_node = sourceNode() + source_node.file_name = file_name + source_node.file_type = 'pdf' + source_node.file_size = '1087' + source_node.file_source = 'local file' + source_node.model = model + source_node.created_at = dt.now() + graphDB_data_Access = graphDBdataAccess(graph) + graphDB_data_Access.create_source_node(source_node) + return source_node + +def test_graph_from_file_local(model_name): + """Test graph creation from a local file.""" + file_name = 'About Amazon.pdf' + shutil.copyfile('/workspaces/llm-graph-builder/backend/files/About Amazon.pdf', + os.path.join(MERGED_DIR, file_name)) + + create_source_node_local(graph, model_name, file_name) + merged_file_path = os.path.join(MERGED_DIR, file_name) + + local_file_result = extract_graph_from_file_local_file( + URI, USERNAME, PASSWORD, DATABASE, model_name, merged_file_path, file_name, '', '',None + ) + logging.info("Local file processing complete") + print(local_file_result) + + try: + assert local_file_result['status'] == 'Completed' + assert local_file_result['nodeCount'] > 0 + assert local_file_result['relationshipCount'] > 0 + print("Success") + except AssertionError as e: + print("Fail: ", e) + + return local_file_result + +def test_graph_from_wikipedia(model_name): + # try: + """Test graph creation from a Wikipedia page.""" + wiki_query = 'https://en.wikipedia.org/wiki/Ram_Mandir' + source_type = 'Wikipedia' + file_name = "Ram_Mandir" + create_source_node_graph_url_wikipedia(graph, model_name, wiki_query, source_type) + + wiki_result = extract_graph_from_file_Wikipedia(URI, USERNAME, PASSWORD, DATABASE, model_name, file_name, 'en',file_name, '', '',None) + logging.info("Wikipedia test done") + print(wiki_result) + try: + assert wiki_result['status'] == 'Completed' + assert wiki_result['nodeCount'] > 0 + assert wiki_result['relationshipCount'] > 0 + print("Success") + except AssertionError as e: + print("Fail: ", e) + + return wiki_result + # except Exception as ex: + # print(ex) + +def test_graph_website(model_name): + """Test graph creation from a Website page.""" + #graph, model, source_url, source_type + source_url = 'https://www.amazon.com/' + source_type = 'web-url' + file_name = [] + create_source_node_graph_web_url(graph, model_name, source_url, source_type) + + weburl_result = extract_graph_from_web_page(URI, USERNAME, PASSWORD, DATABASE, model_name, source_url,file_name, '', '',None) + logging.info("WebUrl test done") + print(weburl_result) + + try: + assert weburl_result['status'] == 'Completed' + assert weburl_result['nodeCount'] > 0 + assert weburl_result['relationshipCount'] > 0 + print("Success") + except AssertionError as e: + print("Fail: ", e) + return weburl_result + +def test_graph_from_youtube_video(model_name): + """Test graph creation from a YouTube video.""" + source_url = 'https://www.youtube.com/watch?v=T-qy-zPWgqA' + source_type = 'youtube' + create_source_node_graph_url_youtube(graph, model_name, source_url, source_type) + youtube_result = extract_graph_from_file_youtube( + URI, USERNAME, PASSWORD, DATABASE, model_name, source_url, '', '' + ) + logging.info("YouTube Video test done") + print(youtube_result) + + try: + assert youtube_result['status'] == 'Completed' + assert youtube_result['nodeCount'] > 1 + assert youtube_result['relationshipCount'] > 1 + print("Success") + except AssertionError as e: + print("Failed: ", e) + + return youtube_result + +def test_chatbot_qna(model_name, mode='vector'): + """Test chatbot QnA functionality for different modes.""" + QA_n_RAG = QA_RAG(graph, model_name, 'Tell me about amazon', '[]', 1, mode) + print(QA_n_RAG) + print(len(QA_n_RAG['message'])) + + + try: + assert len(QA_n_RAG['message']) > 20 + return QA_n_RAG + print("Success") + except AssertionError as e: + print("Failed ", e) + return QA_n_RAG + +#Get Test disconnected_nodes list +def disconected_nodes(): + #graph = create_graph_database_connection(uri, userName, password, database) + graphDb_data_Access = graphDBdataAccess(graph) + nodes_list, total_nodes = graphDb_data_Access.list_unconnected_nodes() + print(nodes_list[0]["e"]["elementId"]) + status = "False" + if total_nodes['total']>0: + status = "True" + else: + status = "False" + return nodes_list[0]["e"]["elementId"], status + +#Test Delete delete_disconnected_nodes list +def delete_disconected_nodes(lst_element_id): + print(f'disconnect elementid list {lst_element_id}') + #graph = create_graph_database_connection(uri, userName, password, database) + graphDb_data_Access = graphDBdataAccess(graph) + result = graphDb_data_Access.delete_unconnected_nodes(json.dumps(lst_element_id)) + print(f'delete disconnect api result {result}') + if not result: + return "True" + else: + return "False" + +#Test Get Duplicate_nodes +def get_duplicate_nodes(): + #graph = create_graph_database_connection(uri, userName, password, database) + graphDb_data_Access = graphDBdataAccess(graph) + nodes_list, total_nodes = graphDb_data_Access.get_duplicate_nodes_list() + if total_nodes['total']>0: + return "True" + else: + return "False" + +#Test populate_graph_schema +def test_populate_graph_schema_from_text(model): + result_schema = populate_graph_schema_from_text('When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble.', model, True) + print(result_schema) + return result_schema + +# def compare_graph_results(results): +# """ +# Compare graph results across different models. +# Add custom logic here to compare graph data, nodes, and relationships. +# """ +# # Placeholder logic for comparison +# print("Comparing results...") +# for i in range(len(results) - 1): +# result_a = results[i] +# result_b = results[i + 1] +# if result_a == result_b: +# print(f"Result {i} is identical to result {i+1}") +# else: +# print(f"Result {i} differs from result {i+1}") + +def run_tests(): + final_list = [] + error_list = [] + models = ['openai-gpt-3.5','openai-gpt-4o','openai-gpt-4o-mini','gemini-1.5-pro','azure_ai_gpt_35','azure_ai_gpt_4o','ollama_llama3','groq_llama3_70b','anthropic_claude_3_5_sonnet','fireworks_v3p1_405b','bedrock_claude_3_5_sonnet'] + + for model_name in models: + try: + # final_list.append(test_graph_from_file_local(model_name)) + # final_list.append(test_graph_from_wikipedia(model_name)) + # final_list.append(test_populate_graph_schema_from_text(model_name)) + # final_list.append(test_graph_website(model_name)) + # final_list.append(test_graph_from_youtube_video(model_name)) + final_list.append(test_chatbot_qna(model_name, mode='entity search+vector')) + + + except Exception as e: + error_list.append((model_name, str(e))) + # #Compare and log diffrences in graph results + # # compare_graph_results(final_list) # Pass the final_list to comapre_graph_results + # test_populate_graph_schema_from_text('openai-gpt-4o') + dis_elementid, dis_status = disconected_nodes() + lst_element_id = [dis_elementid] + delt = delete_disconected_nodes(lst_element_id) +# dup = get_duplicate_nodes() + print(final_list) + # schma = test_populate_graph_schema_from_text(model) + # Save final results to CSV + df = pd.DataFrame(final_list) + print(df) + df['execution_date'] = dt.today().strftime('%Y-%m-%d') + df['disconnected_nodes']=dis_status +# df['get_duplicate_nodes']=dup + df['delete_disconected_nodes']=delt + # df['test_populate_graph_schema_from_text'] = schma + df.to_csv(f"Integration_TestResult_{dt.now().strftime('%Y%m%d_%H%M%S')}.csv", index=False) + + # Save error details to CSV + df_errors = pd.DataFrame(error_list, columns=['Model', 'Error']) + df_errors['execution_date'] = dt.today().strftime('%Y-%m-%d') + df_errors.to_csv(f"Error_details_{dt.now().strftime('%Y%m%d_%H%M%S')}.csv", index=False) + +if __name__ == "__main__": + run_tests() \ No newline at end of file diff --git a/backend/test_integrationqa.py b/backend/test_integrationqa.py index 7b2b110d4..48fdf68c0 100644 --- a/backend/test_integrationqa.py +++ b/backend/test_integrationqa.py @@ -12,7 +12,6 @@ # Load environment variables if needed load_dotenv() - # Constants URI = '' USERNAME = '' @@ -201,7 +200,7 @@ def test_populate_graph_schema_from_text(model): def run_tests(): final_list = [] error_list = [] - models = ['openai-gpt-3.5','openai-gpt-4o','openai-gpt-4o-mini','gemini-1.0-pro','gemini-1.5-pro','azure_ai_gpt_35','azure_ai_gpt_4o','ollama_llama3','groq_llama3_70b','anthropic_claude_3_5_sonnet','fireworks_v3p1_405b','bedrock_claude_3_5_sonnet'] + models = ['openai-gpt-3.5','openai-gpt-4o'] for model_name in models: try: From 6d0e18bc9a654a3f2448155f7088d94e22805689 Mon Sep 17 00:00:00 2001 From: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Date: Thu, 26 Sep 2024 10:35:25 +0000 Subject: [PATCH 129/292] test uupdated --- backend/test_integrationqa.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/backend/test_integrationqa.py b/backend/test_integrationqa.py index 48fdf68c0..832546995 100644 --- a/backend/test_integrationqa.py +++ b/backend/test_integrationqa.py @@ -200,7 +200,7 @@ def test_populate_graph_schema_from_text(model): def run_tests(): final_list = [] error_list = [] - models = ['openai-gpt-3.5','openai-gpt-4o'] + models = ['openai-gpt-3.5','openai-gpt-4o','openai-gpt-4o-mini','gemini-1.0-pro','gemini-1.5-pro','azure_ai_gpt_35','azure_ai_gpt_4o','ollama_llama3','groq_llama3_70b','anthropic_claude_3_5_sonnet','fireworks_v3p1_405b','bedrock_claude_3_5_sonnet'] for model_name in models: try: @@ -208,10 +208,14 @@ def run_tests(): final_list.append(test_graph_from_wikipedia(model_name)) final_list.append(test_populate_graph_schema_from_text(model_name)) final_list.append(test_graph_website(model_name)) - final_list.append(test_graph_from_youtube_video(model_name)) + # final_list.append(test_graph_from_youtube_video(model_name)) final_list.append(test_chatbot_qna(model_name)) final_list.append(test_chatbot_qna(model_name, mode='vector')) + final_list.append(test_chatbot_qna(model_name, mode='graph+vector')) + final_list.append(test_chatbot_qna(model_name, mode='fulltext')) final_list.append(test_chatbot_qna(model_name, mode='graph+vector+fulltext')) + final_list.append(test_chatbot_qna(model_name, mode='entity search+vector')) + except Exception as e: error_list.append((model_name, str(e))) # #Compare and log diffrences in graph results From db02bfa98fb4012404dc5547adfc3eb406d74c86 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Thu, 26 Sep 2024 19:01:25 +0530 Subject: [PATCH 130/292] Read Only User Support (#766) * added local chat history * added write access check * added write access param * added fulltext creation * disabled the write and delete actions for read only user mode * modified query --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> --- backend/score.py | 13 +- backend/src/QA_integration.py | 59 +++- backend/src/graphDB_dataAccess.py | 37 ++- backend/src/main.py | 4 +- backend/src/post_processing.py | 55 +++- frontend/src/components/Content.tsx | 21 +- .../src/components/Layout/DrawerDropzone.tsx | 284 ++++++++++-------- frontend/src/components/Layout/PageLayout.tsx | 3 +- frontend/src/components/Layout/SideNav.tsx | 10 +- .../ConnectionModal/ConnectionModal.tsx | 6 +- frontend/src/context/UserCredentials.tsx | 5 + frontend/src/types.ts | 2 + 12 files changed, 315 insertions(+), 184 deletions(-) diff --git a/backend/score.py b/backend/score.py index 63a26ec5b..92a573aeb 100644 --- a/backend/score.py +++ b/backend/score.py @@ -14,7 +14,7 @@ from src.graphDB_dataAccess import graphDBdataAccess from src.graph_query import get_graph_results from src.chunkid_entities import get_entities_from_chunkids -from src.post_processing import create_fulltext, create_entity_embedding +from src.post_processing import create_fulltext_indexes, create_entity_embedding from sse_starlette.sse import EventSourceResponse from src.communities import create_communities import json @@ -263,14 +263,15 @@ async def post_processing(uri=Form(), userName=Form(), password=Form(), database logging.info(f'Updated KNN Graph') if "enable_hybrid_search_and_fulltext_search_in_bloom" in tasks: - await asyncio.to_thread(create_fulltext, uri=uri, username=userName, password=password, database=database,type="entities") - # await asyncio.to_thread(create_fulltext, uri=uri, username=userName, password=password, database=database,type="keyword") + await asyncio.to_thread(create_fulltext_indexes, uri=uri, username=userName, password=password, database=database) json_obj = {'api_name': 'post_processing/enable_hybrid_search_and_fulltext_search_in_bloom', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} logging.info(f'Full Text index created') + if os.environ.get('ENTITY_EMBEDDING','False').upper()=="TRUE" and "materialize_entity_similarities" in tasks: await asyncio.to_thread(create_entity_embedding, graph) json_obj = {'api_name': 'post_processing/create_entity_embedding', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} logging.info(f'Entity Embeddings created') + if "create_communities" in tasks: model = "openai-gpt-4o" await asyncio.to_thread(create_communities, uri, userName, password, database,model) @@ -298,7 +299,9 @@ async def chat_bot(uri=Form(),model=Form(None),userName=Form(), password=Form(), graph = Neo4jGraph( url=uri,username=userName,password=password,database=database,sanitize = True, refresh_schema=True) else: graph = create_graph_database_connection(uri, userName, password, database) - result = await asyncio.to_thread(QA_RAG,graph=graph,model=model,question=question,document_names=document_names,session_id=session_id,mode=mode) + graph_DB_dataAccess = graphDBdataAccess(graph) + write_access = graph_DB_dataAccess.check_account_access(database=database) + result = await asyncio.to_thread(QA_RAG,graph=graph,model=model,question=question,document_names=document_names,session_id=session_id,mode=mode,write_access=write_access) total_call_time = time.time() - qa_rag_start_time logging.info(f"Total Response time is {total_call_time:.2f} seconds") @@ -384,7 +387,7 @@ async def clear_chat_bot(uri=Form(),userName=Form(), password=Form(), database=F async def connect(uri=Form(), userName=Form(), password=Form(), database=Form()): try: graph = create_graph_database_connection(uri, userName, password, database) - result = await asyncio.to_thread(connection_check_and_get_vector_dimensions, graph) + result = await asyncio.to_thread(connection_check_and_get_vector_dimensions, graph, database) json_obj = {'api_name':'connect','db_url':uri,'status':result, 'count':1, 'logging_time': formatted_time(datetime.now(timezone.utc))} logger.log_struct(json_obj, "INFO") return create_api_response('Success',data=result) diff --git a/backend/src/QA_integration.py b/backend/src/QA_integration.py index 651440437..868508815 100644 --- a/backend/src/QA_integration.py +++ b/backend/src/QA_integration.py @@ -22,6 +22,7 @@ from langchain_text_splitters import TokenTextSplitter from langchain_core.messages import HumanMessage, AIMessage from langchain.chains import GraphCypherQAChain +from langchain_community.chat_message_histories import ChatMessageHistory # LangChain chat models from langchain_openai import ChatOpenAI, AzureChatOpenAI @@ -36,11 +37,33 @@ from src.llm import get_llm from src.shared.common_fn import load_embedding_model from src.shared.constants import * - +from src.graphDB_dataAccess import graphDBdataAccess load_dotenv() EMBEDDING_MODEL = os.getenv('EMBEDDING_MODEL') -EMBEDDING_FUNCTION , _ = load_embedding_model(EMBEDDING_MODEL) +EMBEDDING_FUNCTION , _ = load_embedding_model(EMBEDDING_MODEL) + + + +class SessionChatHistory: + history_dict = {} + + @classmethod + def get_chat_history(cls, session_id): + """Retrieve or create chat message history for a given session ID.""" + if session_id not in cls.history_dict: + logging.info(f"Creating new ChatMessageHistory Local for session ID: {session_id}") + cls.history_dict[session_id] = ChatMessageHistory() + else: + logging.info(f"Retrieved existing ChatMessageHistory Local for session ID: {session_id}") + return cls.history_dict[session_id] + +def get_history_by_session_id(session_id): + try: + return SessionChatHistory.get_chat_history(session_id) + except Exception as e: + logging.error(f"Failed to get history for session ID '{session_id}': {e}") + raise def get_total_tokens(ai_response, llm): try: @@ -71,12 +94,15 @@ def get_total_tokens(ai_response, llm): return total_tokens -def clear_chat_history(graph, session_id): +def clear_chat_history(graph, session_id,local=False): try: - history = Neo4jChatMessageHistory( - graph=graph, - session_id=session_id - ) + if not local: + history = Neo4jChatMessageHistory( + graph=graph, + session_id=session_id + ) + else: + history = get_history_by_session_id(session_id) history.clear() @@ -546,17 +572,20 @@ def process_graph_response(model, graph, question, messages, history): "user": "chatbot" } -def create_neo4j_chat_message_history(graph, session_id): +def create_neo4j_chat_message_history(graph, session_id, write_access=True): """ Creates and returns a Neo4jChatMessageHistory instance. """ try: - - history = Neo4jChatMessageHistory( - graph=graph, - session_id=session_id - ) + if write_access: + history = Neo4jChatMessageHistory( + graph=graph, + session_id=session_id + ) + return history + + history = get_history_by_session_id(session_id) return history except Exception as e: @@ -577,10 +606,10 @@ def get_chat_mode_settings(mode,settings_map=CHAT_MODE_CONFIG_MAP): return chat_mode_settings -def QA_RAG(graph, model, question, document_names, session_id, mode): +def QA_RAG(graph,model, question, document_names, session_id, mode, write_access=True): logging.info(f"Chat Mode: {mode}") - history = create_neo4j_chat_message_history(graph, session_id) + history = create_neo4j_chat_message_history(graph, session_id, write_access) messages = history.messages user_question = HumanMessage(content=question) diff --git a/backend/src/graphDB_dataAccess.py b/backend/src/graphDB_dataAccess.py index 643902b16..c2e2f6424 100644 --- a/backend/src/graphDB_dataAccess.py +++ b/backend/src/graphDB_dataAccess.py @@ -144,6 +144,32 @@ def update_KNN_graph(self): else: logging.info("Vector index does not exist, So KNN graph not update") + def check_account_access(self, database): + query = """ + SHOW USER PRIVILEGES + YIELD * + WHERE graph = $database AND action IN ['read'] + RETURN COUNT(*) AS readAccessCount + """ + try: + logging.info(f"Checking access for database: {database}") + + result = self.graph.query(query, params={"database": database}) + read_access_count = result[0]["readAccessCount"] if result else 0 + + logging.info(f"Read access count: {read_access_count}") + + if read_access_count > 0: + logging.info("The account has read access.") + return False + else: + logging.info("The account has write access.") + return True + + except Exception as e: + logging.error(f"Error checking account access: {e}") + return False + def check_gds_version(self): try: gds_procedure_count = """ @@ -168,7 +194,7 @@ def check_gds_version(self): logging.error(f"An error occurred while checking GDS version: {e}") return False - def connection_check_and_get_vector_dimensions(self): + def connection_check_and_get_vector_dimensions(self,database): """ Get the vector index dimension from database and application configuration and DB connection status @@ -195,18 +221,19 @@ def connection_check_and_get_vector_dimensions(self): logging.info(f'embedding model:{embeddings} and dimesion:{application_dimension}') gds_status = self.check_gds_version() + write_access = self.check_account_access(database=database) if self.graph: if len(db_vector_dimension) > 0: - return {'db_vector_dimension': db_vector_dimension[0]['vector_dimensions'], 'application_dimension':application_dimension, 'message':"Connection Successful","gds_status":gds_status} + return {'db_vector_dimension': db_vector_dimension[0]['vector_dimensions'], 'application_dimension':application_dimension, 'message':"Connection Successful","gds_status":gds_status,"write_access":write_access} else: if len(db_vector_dimension) == 0 and len(result_chunks) == 0: logging.info("Chunks and vector index does not exists in database") - return {'db_vector_dimension': 0, 'application_dimension':application_dimension, 'message':"Connection Successful","chunks_exists":False,"gds_status":gds_status} + return {'db_vector_dimension': 0, 'application_dimension':application_dimension, 'message':"Connection Successful","chunks_exists":False,"gds_status":gds_status,"write_access":write_access} elif len(db_vector_dimension) == 0 and result_chunks[0]['hasEmbedding']==0 and result_chunks[0]['chunks'] > 0: - return {'db_vector_dimension': 0, 'application_dimension':application_dimension, 'message':"Connection Successful","chunks_exists":True,"gds_status":gds_status} + return {'db_vector_dimension': 0, 'application_dimension':application_dimension, 'message':"Connection Successful","chunks_exists":True,"gds_status":gds_status,"write_access":write_access} else: - return {'message':"Connection Successful","gds_status":gds_status} + return {'message':"Connection Successful","gds_status": gds_status,"write_access":write_access} def execute_query(self, query, param=None): return self.graph.query(query, param) diff --git a/backend/src/main.py b/backend/src/main.py index 07773d3d1..9e142a3cb 100644 --- a/backend/src/main.py +++ b/backend/src/main.py @@ -513,7 +513,7 @@ def update_graph(graph): graph_DB_dataAccess.update_KNN_graph() -def connection_check_and_get_vector_dimensions(graph): +def connection_check_and_get_vector_dimensions(graph,database): """ Args: uri: URI of the graph to extract @@ -524,7 +524,7 @@ def connection_check_and_get_vector_dimensions(graph): Returns a status of connection from NEO4j is success or failure """ graph_DB_dataAccess = graphDBdataAccess(graph) - return graph_DB_dataAccess.connection_check_and_get_vector_dimensions() + return graph_DB_dataAccess.connection_check_and_get_vector_dimensions(database) def merge_chunks_local(file_name, total_chunks, chunk_dir, merged_dir): diff --git a/backend/src/post_processing.py b/backend/src/post_processing.py index 7d038c61b..88d99385a 100644 --- a/backend/src/post_processing.py +++ b/backend/src/post_processing.py @@ -10,30 +10,26 @@ FULL_TEXT_QUERY = "CREATE FULLTEXT INDEX entities FOR (n{labels_str}) ON EACH [n.id, n.description];" FILTER_LABELS = ["Chunk","Document","__Community__"] - HYBRID_SEARCH_INDEX_DROP_QUERY = "DROP INDEX keyword IF EXISTS;" -HYBRID_SEARCH_FULL_TEXT_QUERY = "CREATE FULLTEXT INDEX keyword FOR (n:Chunk) ON EACH [n.text]" +HYBRID_SEARCH_FULL_TEXT_QUERY = "CREATE FULLTEXT INDEX keyword FOR (n:Chunk) ON EACH [n.text]" -def create_fulltext(uri, username, password, database,type): - start_time = time.time() - logging.info("Starting the process of creating a full-text index.") +COMMUNITY_INDEX_DROP_QUERY = "DROP INDEX community_keyword IF EXISTS;" +COMMUNITY_INDEX_FULL_TEXT_QUERY = "CREATE FULLTEXT INDEX community_keyword FOR (n:`__Community__`) ON EACH [n.summary]" - try: - driver = GraphDatabase.driver(uri, auth=(username, password), database=database) - driver.verify_connectivity() - logging.info("Database connectivity verified.") - except Exception as e: - logging.error(f"Failed to create a database driver or verify connectivity: {e}") - return +def create_fulltext(driver,type): + + start_time = time.time() try: with driver.session() as session: try: start_step = time.time() if type == "entities": drop_query = DROP_INDEX_QUERY - else: + elif type == "hybrid": drop_query = HYBRID_SEARCH_INDEX_DROP_QUERY + else: + drop_query = COMMUNITY_INDEX_DROP_QUERY session.run(drop_query) logging.info(f"Dropped existing index (if any) in {time.time() - start_step:.2f} seconds.") except Exception as e: @@ -58,8 +54,11 @@ def create_fulltext(uri, username, password, database,type): start_step = time.time() if type == "entities": fulltext_query = FULL_TEXT_QUERY.format(labels_str=labels_str) - else: + elif type == "hybrid": fulltext_query = HYBRID_SEARCH_FULL_TEXT_QUERY + else: + fulltext_query = COMMUNITY_INDEX_FULL_TEXT_QUERY + session.run(fulltext_query) logging.info(f"Created full-text index in {time.time() - start_step:.2f} seconds.") except Exception as e: @@ -68,10 +67,34 @@ def create_fulltext(uri, username, password, database,type): except Exception as e: logging.error(f"An error occurred during the session: {e}") finally: - driver.close() - logging.info("Driver closed.") logging.info(f"Process completed in {time.time() - start_time:.2f} seconds.") + +def create_fulltext_indexes(uri, username, password, database): + types = ["entities", "hybrid", "community"] + logging.info("Starting the process of creating full-text indexes.") + + try: + driver = GraphDatabase.driver(uri, auth=(username, password), database=database) + driver.verify_connectivity() + logging.info("Database connectivity verified.") + except Exception as e: + logging.error(f"An unexpected error occurred: {e}") + return + + for index_type in types: + try: + logging.info(f"Creating a full-text index for type '{index_type}'.") + create_fulltext(driver, index_type) + logging.info(f"Full-text index for type '{index_type}' created successfully.") + except Exception as e: + logging.error(f"Failed to create full-text index for type '{index_type}': {e}") + + logging.info("Full-text indexes creation process completed.") + driver.close() + logging.info("Driver closed.") + + def create_entity_embedding(graph:Neo4jGraph): rows = fetch_entities_for_embedding(graph) for i in range(0, len(rows), 1000): diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index b3efd404c..eeaa56cb6 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -59,8 +59,16 @@ const Content: React.FC = ({ }); const [openGraphView, setOpenGraphView] = useState(false); const [inspectedName, setInspectedName] = useState(''); - const { setUserCredentials, userCredentials, connectionStatus, setConnectionStatus, isGdsActive, setGdsActive } = - useCredentials(); + const { + setUserCredentials, + userCredentials, + connectionStatus, + setConnectionStatus, + isGdsActive, + setGdsActive, + setIsReadOnlyUser, + isReadOnlyUser, + } = useCredentials(); const [showConfirmationModal, setshowConfirmationModal] = useState(false); const [extractLoading, setextractLoading] = useState(false); const [retryFile, setRetryFile] = useState(''); @@ -118,6 +126,9 @@ const Content: React.FC = ({ if (neo4jConnection.isgdsActive !== undefined) { setGdsActive(neo4jConnection.isgdsActive); } + if (neo4jConnection.isReadOnlyUser !== undefined) { + setIsReadOnlyUser(neo4jConnection.isReadOnlyUser); + } } else { setOpenConnection((prev) => ({ ...prev, openPopUp: true })); } @@ -760,7 +771,7 @@ const Content: React.FC = ({ />
    - Neo4j connection + Neo4j connection {isReadOnlyUser ? '(Read only Mode)' : ''} = ({ label='Graph Enhancemnet Settings' className='mr-2.5' onClick={toggleEnhancementDialog} - disabled={!connectionStatus} + disabled={!connectionStatus || isReadOnlyUser} size={isTablet ? 'small' : 'medium'} > Graph Enhancement @@ -887,7 +898,7 @@ const Content: React.FC = ({ } placement='top' onClick={() => setshowDeletePopUp(true)} - disabled={!selectedfileslength} + disabled={!selectedfileslength||isReadOnlyUser} className='ml-0.5' label='Delete Files' size={isTablet ? 'small' : 'medium'} diff --git a/frontend/src/components/Layout/DrawerDropzone.tsx b/frontend/src/components/Layout/DrawerDropzone.tsx index f423f62f9..07d91f642 100644 --- a/frontend/src/components/Layout/DrawerDropzone.tsx +++ b/frontend/src/components/Layout/DrawerDropzone.tsx @@ -11,6 +11,7 @@ import { APP_SOURCES } from '../../utils/Constants'; import GenericButton from '../WebSources/GenericSourceButton'; import GenericModal from '../WebSources/GenericSourceModal'; import FallBackDialog from '../UI/FallBackDialog'; +import { useCredentials } from '../../context/UserCredentials'; const S3Modal = lazy(() => import('../DataSources/AWS/S3Modal')); const GCSModal = lazy(() => import('../DataSources/GCS/GCSModal')); @@ -25,6 +26,7 @@ const DrawerDropzone: React.FC = ({ }) => { const [isBackendConnected, setIsBackendConnected] = useState(false); const { closeAlert, alertState } = useAlertContext(); + const { isReadOnlyUser } = useCredentials(); useEffect(() => { async function getHealthStatus() { @@ -54,143 +56,167 @@ const DrawerDropzone: React.FC = ({ return (
    - - {alertState.showAlert && ( - - )} -
    -
    -
    -
    - {process.env.VITE_ENV != 'PROD' && ( - - - {!isBackendConnected ? : } + {!isReadOnlyUser ? ( + + {alertState.showAlert && ( + + )} +
    +
    +
    +
    + {process.env.VITE_ENV != 'PROD' && ( + + + {!isBackendConnected ? : } + + Backend connection status - Backend connection status - - )} -
    - {process.env.VITE_ENV != 'PROD' ? ( - <> - - {APP_SOURCES != undefined && APP_SOURCES.includes('local') && ( -
    - -
    - )} - {(APP_SOURCES != undefined && APP_SOURCES.includes('s3')) || - (APP_SOURCES != undefined && APP_SOURCES.includes('gcs')) ? ( - <> - {(APP_SOURCES.includes('youtube') || - APP_SOURCES.includes('wiki') || - APP_SOURCES.includes('web')) && ( -
    - - -
    - )} - {APP_SOURCES.includes('s3') && ( -
    - - }> - - -
    - )} - {APP_SOURCES.includes('gcs') && ( -
    - - }> + )} +
    + {process.env.VITE_ENV != 'PROD' ? ( + <> + + {APP_SOURCES != undefined && APP_SOURCES.includes('local') && ( +
    + +
    + )} + {(APP_SOURCES != undefined && APP_SOURCES.includes('s3')) || + (APP_SOURCES != undefined && APP_SOURCES.includes('gcs')) ? ( + <> + {(APP_SOURCES.includes('youtube') || + APP_SOURCES.includes('wiki') || + APP_SOURCES.includes('web')) && ( +
    + + +
    + )} + {APP_SOURCES.includes('s3') && ( +
    + + }> + + +
    + )} + {APP_SOURCES.includes('gcs') && ( +
    + + }> + + +
    + )} + + ) : ( + <> + )} +
    + + ) : ( + <> + + {APP_SOURCES != undefined && APP_SOURCES.includes('local') && ( +
    + +
    + )} + {((APP_SOURCES != undefined && APP_SOURCES.includes('youtube')) || + (APP_SOURCES != undefined && APP_SOURCES.includes('wiki')) || + (APP_SOURCES != undefined && APP_SOURCES.includes('web'))) && ( +
    + + +
    + )} + {(APP_SOURCES != undefined && APP_SOURCES.includes('s3')) || + (APP_SOURCES != undefined && APP_SOURCES.includes('gcs')) ? ( + <> + {APP_SOURCES != undefined && APP_SOURCES.includes('s3') && ( +
    + + }> + + +
    + )} + {APP_SOURCES != undefined && APP_SOURCES.includes('gcs') && ( +
    + - -
    - )} - - ) : ( - <> - )} -
    - - ) : ( - <> - - {APP_SOURCES != undefined && APP_SOURCES.includes('local') && ( -
    - -
    - )} - {((APP_SOURCES != undefined && APP_SOURCES.includes('youtube')) || - (APP_SOURCES != undefined && APP_SOURCES.includes('wiki')) || - (APP_SOURCES != undefined && APP_SOURCES.includes('web'))) && ( -
    - - -
    - )} - {(APP_SOURCES != undefined && APP_SOURCES.includes('s3')) || - (APP_SOURCES != undefined && APP_SOURCES.includes('gcs')) ? ( - <> - {APP_SOURCES != undefined && APP_SOURCES.includes('s3') && ( -
    - - }> - - -
    - )} - {APP_SOURCES != undefined && APP_SOURCES.includes('gcs') && ( -
    - - -
    - )} - - ) : ( - <> - )} -
    - - )} +
    + )} + + ) : ( + <> + )} + + + )} +
    -
    - + + ) : ( + + + This user account does not have permission to access or manage data sources. + + + )}
    ); diff --git a/frontend/src/components/Layout/PageLayout.tsx b/frontend/src/components/Layout/PageLayout.tsx index c2c21116c..07d795484 100644 --- a/frontend/src/components/Layout/PageLayout.tsx +++ b/frontend/src/components/Layout/PageLayout.tsx @@ -22,6 +22,7 @@ export default function PageLayoutNew({ openSettingsDialog: () => void; }) { const largedesktops = useMediaQuery(`(min-width:1440px )`); + const { userCredentials, connectionStatus } = useCredentials(); const [isLeftExpanded, setIsLeftExpanded] = useState(Boolean(largedesktops)); const [isRightExpanded, setIsRightExpanded] = useState(Boolean(largedesktops)); const [showChatBot, setShowChatBot] = useState(false); @@ -31,7 +32,7 @@ export default function PageLayoutNew({ const [shows3Modal, toggleS3Modal] = useReducer((s) => !s, false); const [showGCSModal, toggleGCSModal] = useReducer((s) => !s, false); const [showGenericModal, toggleGenericModal] = useReducer((s) => !s, false); - const { userCredentials, connectionStatus } = useCredentials(); + const toggleLeftDrawer = () => { if (largedesktops) { setIsLeftExpanded(!isLeftExpanded); diff --git a/frontend/src/components/Layout/SideNav.tsx b/frontend/src/components/Layout/SideNav.tsx index bdc43c8be..ee3ef510b 100644 --- a/frontend/src/components/Layout/SideNav.tsx +++ b/frontend/src/components/Layout/SideNav.tsx @@ -44,7 +44,7 @@ const SideNav: React.FC = ({ const [chatModeAnchor, setchatModeAnchor] = useState(null); const [showChatMode, setshowChatMode] = useState(false); const largedesktops = useMediaQuery(`(min-width:1440px )`); - const { connectionStatus } = useCredentials(); + const { connectionStatus, isReadOnlyUser } = useCredentials(); const date = new Date(); useEffect(() => { @@ -125,7 +125,7 @@ const SideNav: React.FC = ({ /> )} - {!largedesktops && position === 'left' && ( + {!largedesktops && position === 'left' && !isReadOnlyUser && ( @@ -137,7 +137,7 @@ const SideNav: React.FC = ({ } /> )} - {!largedesktops && APP_SOURCES.includes('gcs') && position === 'left' && ( + {!largedesktops && APP_SOURCES.includes('gcs') && position === 'left' && !isReadOnlyUser && ( @@ -149,7 +149,7 @@ const SideNav: React.FC = ({ } /> )} - {!largedesktops && APP_SOURCES.includes('s3') && position === 'left' && ( + {!largedesktops && APP_SOURCES.includes('s3') && position === 'left' && !isReadOnlyUser && ( @@ -161,7 +161,7 @@ const SideNav: React.FC = ({ } /> )} - {!largedesktops && APP_SOURCES.includes('web') && position === 'left' && ( + {!largedesktops && APP_SOURCES.includes('web') && position === 'left' && !isReadOnlyUser && ( diff --git a/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx b/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx index 0213e9502..618cc7b80 100644 --- a/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx +++ b/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx @@ -41,7 +41,7 @@ export default function ConnectionModal({ const [username, setUsername] = useState(initialusername ?? 'neo4j'); const [password, setPassword] = useState(''); const [connectionMessage, setMessage] = useState({ type: 'unknown', content: '' }); - const { setUserCredentials, userCredentials, setGdsActive } = useCredentials(); + const { setUserCredentials, userCredentials, setGdsActive, setIsReadOnlyUser } = useCredentials(); const [isLoading, setIsLoading] = useState(false); const [searchParams, setSearchParams] = useSearchParams(); const [userDbVectorIndex, setUserDbVectorIndex] = useState(initialuserdbvectorindex ?? undefined); @@ -208,7 +208,10 @@ export default function ConnectionModal({ throw new Error(response.data.error); } else { const isgdsActive = response.data.data.gds_status; + const isReadOnlyUser = !response.data.data.write_access; setGdsActive(isgdsActive); + console.log({ isReadOnlyUser }); + setIsReadOnlyUser(isReadOnlyUser); localStorage.setItem( 'neo4j.connection', JSON.stringify({ @@ -218,6 +221,7 @@ export default function ConnectionModal({ database: database, userDbVectorIndex, isgdsActive, + isReadOnlyUser, }) ); setUserDbVectorIndex(response.data.data.db_vector_dimension); diff --git a/frontend/src/context/UserCredentials.tsx b/frontend/src/context/UserCredentials.tsx index 1b5eda2da..cd3db2d62 100644 --- a/frontend/src/context/UserCredentials.tsx +++ b/frontend/src/context/UserCredentials.tsx @@ -12,6 +12,8 @@ export const UserConnection = createContext({ setGdsActive: () => false, connectionStatus: false, setConnectionStatus: () => null, + isReadOnlyUser: false, + setIsReadOnlyUser: () => null, }); export const useCredentials = () => { const userCredentials = useContext(UserConnection); @@ -20,6 +22,7 @@ export const useCredentials = () => { const UserCredentialsWrapper: FunctionComponent = (props) => { const [userCredentials, setUserCredentials] = useState(null); const [isGdsActive, setGdsActive] = useState(false); + const [isReadOnlyUser, setIsReadOnlyUser] = useState(false); const [connectionStatus, setConnectionStatus] = useReducer((state) => !state, false); const value = { userCredentials, @@ -28,6 +31,8 @@ const UserCredentialsWrapper: FunctionComponent = (props) => { setGdsActive, connectionStatus, setConnectionStatus, + isReadOnlyUser, + setIsReadOnlyUser, }; return {props.children}; diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 9631335a9..10f16e4d6 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -631,6 +631,8 @@ export interface ContextProps { setUserCredentials: (UserCredentials: UserCredentials) => void; isGdsActive: boolean; setGdsActive: Dispatch>; + isReadOnlyUser: boolean; + setIsReadOnlyUser: Dispatch>; connectionStatus: boolean; setConnectionStatus: Dispatch>; } From c7460de4f39e999716607f84d2ba24cc1f2ec583 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Thu, 26 Sep 2024 13:34:37 +0000 Subject: [PATCH 131/292] storing the gds status and write access on refresh --- frontend/src/components/Content.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index eeaa56cb6..e88ff72a3 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -200,6 +200,12 @@ const Content: React.FC = ({ password: btoa(atob(parsedData.password)), }) ); + if (response.data.data.gds_status !== undefined) { + setGdsActive(response.data.data.gds_status); + } + if (response.data.data.write_access !== undefined) { + setIsReadOnlyUser(response.data.data.write_access); + } if ( (response.data.data.application_dimension === response.data.data.db_vector_dimension || response.data.data.db_vector_dimension == 0) && @@ -898,7 +904,7 @@ const Content: React.FC = ({ } placement='top' onClick={() => setshowDeletePopUp(true)} - disabled={!selectedfileslength||isReadOnlyUser} + disabled={!selectedfileslength || isReadOnlyUser} className='ml-0.5' label='Delete Files' size={isTablet ? 'small' : 'medium'} From ba6a9d2834b7fa23f3f70bf5b31b675f999af5d3 Mon Sep 17 00:00:00 2001 From: aashipandya <156318202+aashipandya@users.noreply.github.com> Date: Fri, 27 Sep 2024 12:59:21 +0530 Subject: [PATCH 132/292] Langchain libs update (#769) * LLMs with latest langchain dev libraries * conflict resolved * all llm models with latest library changes --- backend/requirements.txt | 33 ++++++++-------- backend/src/llm.py | 10 +++-- backend/src/main.py | 16 ++++---- backend/src/shared/constants.py | 52 +++++++++++++++++++++++-- backend/src/shared/schema_extraction.py | 3 +- frontend/src/utils/Constants.ts | 3 +- 6 files changed, 83 insertions(+), 34 deletions(-) diff --git a/backend/requirements.txt b/backend/requirements.txt index 158458ce1..30b767939 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -69,22 +69,22 @@ jsonpath-python==1.0.6 jsonpointer==2.4 json-repair==0.25.2 kiwisolver==1.4.5 -langchain -langchain-aws -langchain-anthropic -langchain-fireworks -langchain-google-genai -langchain-community -langchain-core -langchain-experimental -langchain-google-vertexai -langchain-groq -langchain-openai -langchain-text-splitters +langchain==0.3.0 +langchain-aws==0.2.1 +langchain-anthropic==0.2.1 +langchain-fireworks==0.2.0 +langchain-google-genai==2.0.0 +langchain-community==0.3.0 +langchain-core==0.3.5 +langchain-experimental==0.3.1 +langchain-google-vertexai==2.0.1 +langchain-groq==0.2.0 +langchain-openai==0.2.0 +langchain-text-splitters==0.3.0 langdetect==1.0.9 -langsmith==0.1.83 +langsmith==0.1.128 layoutparser==0.3.4 -langserve==0.2.2 +langserve==0.3.0 #langchain-cli==0.0.25 lxml==5.1.0 MarkupSafe==2.1.5 @@ -100,7 +100,7 @@ numpy==1.26.4 omegaconf==2.3.0 onnx==1.16.1 onnxruntime==1.18.1 -openai==1.35.10 +openai==1.47.1 opencv-python==4.8.0.76 orjson==3.9.15 packaging==23.2 @@ -144,7 +144,6 @@ shapely==2.0.3 six==1.16.0 sniffio==1.3.1 soupsieve==2.5 -SQLAlchemy==2.0.28 starlette==0.37.2 sse-starlette==2.1.2 starlette-session==0.4.3 @@ -159,7 +158,7 @@ transformers==4.42.3 types-protobuf types-requests typing-inspect==0.9.0 -typing_extensions==4.9.0 +typing_extensions==4.12.2 tzdata==2024.1 unstructured==0.14.9 unstructured-client==0.23.8 diff --git a/backend/src/llm.py b/backend/src/llm.py index 505bb89fb..c2335685f 100644 --- a/backend/src/llm.py +++ b/backend/src/llm.py @@ -9,13 +9,14 @@ import concurrent.futures from concurrent.futures import ThreadPoolExecutor from langchain_experimental.graph_transformers import LLMGraphTransformer +from langchain_core.prompts import ChatPromptTemplate from langchain_anthropic import ChatAnthropic from langchain_fireworks import ChatFireworks from langchain_aws import ChatBedrock from langchain_community.chat_models import ChatOllama import boto3 import google.auth -from src.shared.constants import MODEL_VERSIONS +from src.shared.constants import MODEL_VERSIONS, PROMPT_TO_ALL_LLMs def get_llm(model: str): @@ -28,7 +29,7 @@ def get_llm(model: str): model_name = MODEL_VERSIONS[model] llm = ChatVertexAI( model_name=model_name, - convert_system_message_to_human=True, + #convert_system_message_to_human=True, credentials=credentials, project=project_id, temperature=0, @@ -149,8 +150,9 @@ def get_graph_document_list( if "diffbot_api_key" in dir(llm): llm_transformer = llm else: - if "get_name" in dir(llm) and llm.get_name() == "ChatOllama": + if "get_name" in dir(llm) and llm.get_name() != "ChatOenAI" or llm.get_name() != "ChatVertexAI" or llm.get_name() != "AzureChatOpenAI": node_properties = False + relationship_properties = False else: node_properties = ["description"] relationship_properties = ["description"] @@ -160,6 +162,8 @@ def get_graph_document_list( relationship_properties=relationship_properties, allowed_nodes=allowedNodes, allowed_relationships=allowedRelationship, + ignore_tool_usage=True, + #prompt = ChatPromptTemplate.from_messages(["system",PROMPT_TO_ALL_LLMs]) ) with ThreadPoolExecutor(max_workers=10) as executor: for chunk in combined_chunk_document_list: diff --git a/backend/src/main.py b/backend/src/main.py index 9e142a3cb..41942d500 100644 --- a/backend/src/main.py +++ b/backend/src/main.py @@ -433,14 +433,14 @@ def processing_chunks(chunkId_chunkDoc_list,graph,uri, userName, password, datab node_type= node.type if (node_id, node_type) not in distinct_nodes: distinct_nodes.add((node_id, node_type)) - #get all relations - for relation in graph_document.relationships: - relations.append(relation.type) - - node_count += len(distinct_nodes) - rel_count += len(relations) - print(f'node count internal func:{node_count}') - print(f'relation count internal func:{rel_count}') + #get all relations + for relation in graph_document.relationships: + relations.append(relation.type) + + node_count += len(distinct_nodes) + rel_count += len(relations) + print(f'node count internal func:{node_count}') + print(f'relation count internal func:{rel_count}') return node_count,rel_count def get_chunkId_chunkDoc_list(graph, file_name, pages, retry_condition): diff --git a/backend/src/shared/constants.py b/backend/src/shared/constants.py index bbf579520..f76812553 100644 --- a/backend/src/shared/constants.py +++ b/backend/src/shared/constants.py @@ -1,7 +1,8 @@ MODEL_VERSIONS = { "openai-gpt-3.5": "gpt-3.5-turbo-0125", "gemini-1.0-pro": "gemini-1.0-pro-001", - "gemini-1.5-pro": "gemini-1.5-pro-preview-0514", + "gemini-1.5-pro": "gemini-1.5-pro-002", + "gemini-1.5-flash": "gemini-1.5-flash-002", "openai-gpt-4": "gpt-4-turbo-2024-04-09", "diffbot" : "gpt-4-turbo-2024-04-09", "openai-gpt-4o-mini": "gpt-4o-mini-2024-07-18", @@ -9,7 +10,7 @@ "groq-llama3" : "llama3-70b-8192" } OPENAI_MODELS = ["openai-gpt-3.5", "openai-gpt-4o", "openai-gpt-4o-mini"] -GEMINI_MODELS = ["gemini-1.0-pro", "gemini-1.5-pro"] +GEMINI_MODELS = ["gemini-1.0-pro", "gemini-1.5-pro", "gemini-1.5-flash"] GROQ_MODELS = ["groq-llama3"] BUCKET_UPLOAD = 'llm-graph-builder-upload' BUCKET_FAILED_FILE = 'llm-graph-builder-failed' @@ -92,14 +93,14 @@ CHAT_DOC_SPLIT_SIZE = 3000 CHAT_EMBEDDING_FILTER_SCORE_THRESHOLD = 0.10 CHAT_TOKEN_CUT_OFF = { - ("openai-gpt-3.5",'azure_ai_gpt_35',"gemini-1.0-pro","gemini-1.5-pro","groq-llama3",'groq_llama3_70b','anthropic_claude_3_5_sonnet','fireworks_llama_v3_70b','bedrock_claude_3_5_sonnet', ) : 4, + ("openai-gpt-3.5",'azure_ai_gpt_35',"gemini-1.0-pro","gemini-1.5-pro","gemini-1.5-flash","groq-llama3",'groq_llama3_70b','anthropic_claude_3_5_sonnet','fireworks_llama_v3_70b','bedrock_claude_3_5_sonnet', ) : 4, ("openai-gpt-4","diffbot" ,'azure_ai_gpt_4o',"openai-gpt-4o", "openai-gpt-4o-mini") : 28, ("ollama_llama3") : 2 } CHAT_TOKEN_CUT_OFF = { - ("openai-gpt-3.5",'azure_ai_gpt_35',"gemini-1.0-pro","gemini-1.5-pro","groq-llama3",'groq_llama3_70b','anthropic_claude_3_5_sonnet','fireworks_llama_v3_70b','bedrock_claude_3_5_sonnet', ) : 4, + ("openai-gpt-3.5",'azure_ai_gpt_35',"gemini-1.0-pro","gemini-1.5-pro", "gemini-1.5-flash","groq-llama3",'groq_llama3_70b','anthropic_claude_3_5_sonnet','fireworks_llama_v3_70b','bedrock_claude_3_5_sonnet', ) : 4, ("openai-gpt-4","diffbot" ,'azure_ai_gpt_4o',"openai-gpt-4o", "openai-gpt-4o-mini") : 28, ("ollama_llama3") : 2 } @@ -476,3 +477,46 @@ START_FROM_BEGINNING = "start_from_beginning" DELETE_ENTITIES_AND_START_FROM_BEGINNING = "delete_entities_and_start_from_beginning" START_FROM_LAST_PROCESSED_POSITION = "start_from_last_processed_position" + +PROMPT_TO_ALL_LLMs = """ +"# Knowledge Graph Instructions for LLMs\n" + "## 1. Overview\n" + "You are a top-tier algorithm designed for extracting information in structured " + "formats to build a knowledge graph.\n" + "Try to capture as much information from the text as possible without " + "sacrificing accuracy. Do not add any information that is not explicitly " + "mentioned in the text.\n" + "- **Nodes** represent entities and concepts.\n" + "- The aim is to achieve simplicity and clarity in the knowledge graph, making it\n" + "accessible for a vast audience.\n" + "## 2. Labeling Nodes\n" + "- **Consistency**: Ensure you use available types for node labels.\n" + "Ensure you use basic or elementary types for node labels.\n" + "- For example, when you identify an entity representing a person, " + "always label it as **'person'**. Avoid using more specific terms " + "like 'mathematician' or 'scientist'." + "- **Node IDs**: Never utilize integers as node IDs. Node IDs should be " + "names or human-readable identifiers found in the text.\n" + "- **Relationships** represent connections between entities or concepts.\n" + "Ensure consistency and generality in relationship types when constructing " + "knowledge graphs. Instead of using specific and momentary types " + "such as 'BECAME_PROFESSOR', use more general and timeless relationship types " + "like 'PROFESSOR'. Make sure to use general and timeless relationship types!\n" + "## 3. Coreference Resolution\n" + "- **Maintain Entity Consistency**: When extracting entities, it's vital to " + "ensure consistency.\n" + 'If an entity, such as "John Doe", is mentioned multiple times in the text ' + 'but is referred to by different names or pronouns (e.g., "Joe", "he"),' + "always use the most complete identifier for that entity throughout the " + 'knowledge graph. In this example, use "John Doe" as the entity ID.\n' + "Remember, the knowledge graph should be coherent and easily understandable, " + "so maintaining consistency in entity references is crucial.\n" + "## 4. Node Properties\n" + "- Dates, URLs, Time, and Numerical Values: Instead of creating separate nodes for + these elements, represent them as properties of existing nodes." + "- Example: Instead of creating a node labeled "2023-03-15" and connecting it to another node + with the relationship "BORN_ON", add a property called "born_on" to the person node with the + value "2023-03-15"." + "## 5. Strict Compliance\n" + "Adhere to the rules strictly. Non-compliance will result in termination." + """ \ No newline at end of file diff --git a/backend/src/shared/schema_extraction.py b/backend/src/shared/schema_extraction.py index 27008acae..80954ba65 100644 --- a/backend/src/shared/schema_extraction.py +++ b/backend/src/shared/schema_extraction.py @@ -1,5 +1,6 @@ from typing import List -from langchain_core.pydantic_v1 import BaseModel, Field +#from langchain_core.pydantic_v1 import BaseModel, Field +from pydantic.v1 import BaseModel, Field from src.llm import get_llm from src.shared.constants import MODEL_VERSIONS from langchain_core.prompts import ChatPromptTemplate diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index cf37e9313..08948ba87 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -45,12 +45,13 @@ export const llms = 'openai-gpt-4o-mini', 'gemini-1.0-pro', 'gemini-1.5-pro', + 'gemini-1.5-flash', 'azure_ai_gpt_35', 'azure_ai_gpt_4o', 'ollama_llama3', 'groq_llama3_70b', 'anthropic_claude_3_5_sonnet', - 'fireworks_v3p1_405b', + 'fireworks_llama_v3p2_90b', 'bedrock_claude_3_5_sonnet', ]; From 3c2e3448598750e943b545f0947460a2658e7f2c Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Fri, 27 Sep 2024 08:41:00 +0000 Subject: [PATCH 133/292] fixed the rerendering of the table while file status is processing --- frontend/src/hooks/useSse.tsx | 37 +++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/frontend/src/hooks/useSse.tsx b/frontend/src/hooks/useSse.tsx index 8b063751c..dadf4d184 100644 --- a/frontend/src/hooks/useSse.tsx +++ b/frontend/src/hooks/useSse.tsx @@ -8,6 +8,7 @@ export default function useServerSideEvent( errorHandler: (filename: string) => void ) { const { setFilesData, setProcessedCount } = useFileContext(); + const processcountmap: Record = {}; function updateStatusForLargeFiles(eventSourceRes: eventResponsetypes) { const { fileName, @@ -28,22 +29,26 @@ export default function useServerSideEvent( alertHandler(minutes !== 0, minutes === 0 ? seconds : minutes, fileName); } if (total_chunks) { - setFilesData((prevfiles) => { - return prevfiles.map((curfile) => { - if (curfile.name == fileName) { - return { - ...curfile, - status: total_chunks === processed_chunk ? 'Completed' : status, - NodesCount: nodeCount, - relationshipCount: relationshipCount, - model: model, - processing: processingTime?.toFixed(2), - processingProgress: Math.floor((processed_chunk / total_chunks) * 100), - }; - } - return curfile; + const updateState = processed_chunk != processcountmap[fileName]; + if (updateState) { + processcountmap[fileName] = processed_chunk; + setFilesData((prevfiles) => { + return prevfiles.map((curfile) => { + if (curfile.name == fileName) { + return { + ...curfile, + status: total_chunks === processed_chunk ? 'Completed' : status, + NodesCount: nodeCount, + relationshipCount: relationshipCount, + model: model, + processing: processingTime?.toFixed(2), + processingProgress: Math.floor((processed_chunk / total_chunks) * 100), + }; + } + return curfile; + }); }); - }); + } } } else if (status === 'Completed') { setFilesData((prevfiles) => { @@ -67,6 +72,7 @@ export default function useServerSideEvent( } return prev + 1; }); + delete processcountmap[fileName]; } else if (eventSourceRes.status === 'Failed') { setFilesData((prevfiles) => { return prevfiles.map((curfile) => { @@ -80,6 +86,7 @@ export default function useServerSideEvent( }); }); errorHandler(fileName); + delete processcountmap[fileName]; } } return { From 0d93f57e8b2fb2477daa15e4dd4b8b49d934d035 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Fri, 27 Sep 2024 08:50:27 +0000 Subject: [PATCH 134/292] fix: Read Only User Fix --- frontend/src/components/Content.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index e88ff72a3..0995426c1 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -204,7 +204,7 @@ const Content: React.FC = ({ setGdsActive(response.data.data.gds_status); } if (response.data.data.write_access !== undefined) { - setIsReadOnlyUser(response.data.data.write_access); + setIsReadOnlyUser(!response.data.data.write_access); } if ( (response.data.data.application_dimension === response.data.data.db_vector_dimension || From dc994a2a5f1e0807b41a0ad0348551262ab22999 Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Fri, 27 Sep 2024 14:32:57 +0530 Subject: [PATCH 135/292] Global search fulltext (#767) * added global search+vector+fulltext mode * added community details in chunk entities * added node ids * updated vector graph query * added entities and modified chat response * added params * api response changes * added chunk entity query * modifies query * payload changes * added nodetails properties * payload new changes * communities check * communities selecetion check * Communities bug solutions (#770) * added local chat history * added write access check * added write access param * labels cahnge for nodes * added fulltext creation * disabled the write and delete actions for read only user mode * modified query * test updates * test uupdated * enable communities * removed the selected prop * Read Only User Support (#766) * added local chat history * added write access check * added write access param * added fulltext creation * disabled the write and delete actions for read only user mode * modified query --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * storing the gds status and write access on refresh * enable communities label change --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> * readonly fixed on refresh * clear chat history * slectedFiles check for Chatbot * clear history --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> --- backend/score.py | 9 +- backend/src/QA_integration.py | 86 ++-- backend/src/chunkid_entities.py | 104 ++-- backend/src/shared/constants.py | 444 +++++++++++++----- .../src/components/ChatBot/ChatInfoModal.tsx | 89 ++-- .../src/components/ChatBot/ChatModeToggle.tsx | 40 +- frontend/src/components/ChatBot/Chatbot.tsx | 65 ++- .../src/components/ChatBot/Communities.tsx | 5 + frontend/src/components/Content.tsx | 37 +- .../components/Graph/CheckboxSelection.tsx | 20 +- .../src/components/Graph/GraphViewModal.tsx | 34 +- frontend/src/components/Layout/PageLayout.tsx | 3 +- frontend/src/components/Layout/SideNav.tsx | 1 - .../PostProcessingCheckList/index.tsx | 2 +- frontend/src/context/UserMessages.tsx | 3 + frontend/src/context/UsersFiles.tsx | 47 +- frontend/src/services/ChunkEntitiesInfo.ts | 12 +- frontend/src/types.ts | 78 ++- frontend/src/utils/Constants.ts | 9 +- frontend/src/utils/Utils.ts | 13 + 20 files changed, 709 insertions(+), 392 deletions(-) diff --git a/backend/score.py b/backend/score.py index 92a573aeb..a9e8e0b93 100644 --- a/backend/score.py +++ b/backend/score.py @@ -271,8 +271,8 @@ async def post_processing(uri=Form(), userName=Form(), password=Form(), database await asyncio.to_thread(create_entity_embedding, graph) json_obj = {'api_name': 'post_processing/create_entity_embedding', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} logging.info(f'Entity Embeddings created') - - if "create_communities" in tasks: + + if "enable_communities" in tasks: model = "openai-gpt-4o" await asyncio.to_thread(create_communities, uri, userName, password, database,model) josn_obj = {'api_name': 'post_processing/create_communities', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} @@ -321,10 +321,9 @@ async def chat_bot(uri=Form(),model=Form(None),userName=Form(), password=Form(), gc.collect() @app.post("/chunk_entities") -async def chunk_entities(uri=Form(),userName=Form(), password=Form(), database=Form(), chunk_ids=Form(None),is_entity=Form()): +async def chunk_entities(uri=Form(),userName=Form(), password=Form(), database=Form(), nodedetails=Form(None),entities=Form(),mode=Form()): try: - logging.info(f"URI: {uri}, Username: {userName}, chunk_ids: {chunk_ids}") - result = await asyncio.to_thread(get_entities_from_chunkids,uri=uri, username=userName, password=password, database=database,chunk_ids=chunk_ids,is_entity=json.loads(is_entity.lower())) + result = await asyncio.to_thread(get_entities_from_chunkids,uri=uri, username=userName, password=password, database=database,nodedetails=nodedetails,entities=entities,mode=mode) json_obj = {'api_name':'chunk_entities','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} logger.log_struct(json_obj, "INFO") return create_api_response('Success',data=result) diff --git a/backend/src/QA_integration.py b/backend/src/QA_integration.py index 868508815..169d2b8c3 100644 --- a/backend/src/QA_integration.py +++ b/backend/src/QA_integration.py @@ -147,7 +147,6 @@ def get_sources_and_chunks(sources_used, docs): result = { 'sources': sources_used, 'chunkdetails': chunkdetails_list, - "entities" : list() } return result @@ -182,16 +181,19 @@ def format_documents(documents, model): sorted_documents = sorted(documents, key=lambda doc: doc.state.get("query_similarity_score", 0), reverse=True) sorted_documents = sorted_documents[:prompt_token_cutoff] - formatted_docs = [] + formatted_docs = list() sources = set() - lc_entities = {'entities':list()} + entities = dict() + global_communities = list() + for doc in sorted_documents: try: source = doc.metadata.get('source', "unknown") sources.add(source) - lc_entities = doc.metadata if 'entities'in doc.metadata.keys() else lc_entities + entities = doc.metadata['entities'] if 'entities'in doc.metadata.keys() else entities + global_communities = doc.metadata["communitydetails"] if 'communitydetails'in doc.metadata.keys() else global_communities formatted_doc = ( "Document start\n" @@ -204,13 +206,13 @@ def format_documents(documents, model): except Exception as e: logging.error(f"Error formatting document: {e}") - return "\n\n".join(formatted_docs), sources,lc_entities + return "\n\n".join(formatted_docs), sources,entities,global_communities def process_documents(docs, question, messages, llm, model,chat_mode_settings): start_time = time.time() try: - formatted_docs, sources,lc_entities = format_documents(docs, model) + formatted_docs, sources, entitydetails, communities = format_documents(docs, model) rag_chain = get_rag_chain(llm=llm) @@ -219,12 +221,25 @@ def process_documents(docs, question, messages, llm, model,chat_mode_settings): "context": formatted_docs, "input": question }) - if chat_mode_settings["mode"] == "entity search+vector": - result = {'sources': list(), - 'chunkdetails': list()} - result.update(lc_entities) + + result = {'sources': list(), 'nodedetails': dict(), 'entities': dict()} + node_details = {"chunkdetails":list(),"entitydetails":list(),"communitydetails":list()} + entities = {'entityids':list(),"relationshipids":list()} + + if chat_mode_settings["mode"] == CHAT_ENTITY_VECTOR_MODE: + node_details["entitydetails"] = entitydetails + + elif chat_mode_settings["mode"] == CHAT_GLOBAL_VECTOR_FULLTEXT_MODE: + node_details["communitydetails"] = communities else: - result = get_sources_and_chunks(sources, docs) + sources_and_chunks = get_sources_and_chunks(sources, docs) + result['sources'] = sources_and_chunks['sources'] + node_details["chunkdetails"] = sources_and_chunks["chunkdetails"] + entities.update(entitydetails) + + result["nodedetails"] = node_details + result["entities"] = entities + content = ai_response.content total_tokens = get_total_tokens(ai_response, llm) @@ -295,10 +310,13 @@ def create_document_retriever_chain(llm, retriever): def initialize_neo4j_vector(graph, chat_mode_settings): try: - mode = chat_mode_settings.get('mode', 'undefined') retrieval_query = chat_mode_settings.get("retrieval_query") index_name = chat_mode_settings.get("index_name") keyword_index = chat_mode_settings.get("keyword_index", "") + node_label = chat_mode_settings.get("node_label") + embedding_node_property = chat_mode_settings.get("embedding_node_property") + text_node_properties = chat_mode_settings.get("text_node_properties") + if not retrieval_query or not index_name: raise ValueError("Required settings 'retrieval_query' or 'index_name' are missing.") @@ -310,28 +328,21 @@ def initialize_neo4j_vector(graph, chat_mode_settings): retrieval_query=retrieval_query, graph=graph, search_type="hybrid", - node_label="Chunk", - embedding_node_property="embedding", - text_node_properties=["text"], + node_label=node_label, + embedding_node_property=embedding_node_property, + text_node_properties=text_node_properties, keyword_index_name=keyword_index ) logging.info(f"Successfully retrieved Neo4jVector Fulltext index '{index_name}' and keyword index '{keyword_index}'") - elif mode == "entity search+vector": - neo_db = Neo4jVector.from_existing_index( - embedding=EMBEDDING_FUNCTION, - index_name=index_name, - retrieval_query=retrieval_query, - graph=graph - ) else: neo_db = Neo4jVector.from_existing_graph( embedding=EMBEDDING_FUNCTION, index_name=index_name, retrieval_query=retrieval_query, graph=graph, - node_label="Chunk", - embedding_node_property="embedding", - text_node_properties=["text"] + node_label=node_label, + embedding_node_property=embedding_node_property, + text_node_properties=text_node_properties ) logging.info(f"Successfully retrieved Neo4jVector index '{index_name}'") except Exception as e: @@ -359,12 +370,12 @@ def create_retriever(neo_db, document_names, chat_mode_settings,search_k, score_ logging.info(f"Successfully created retriever with search_k={search_k}, score_threshold={score_threshold}") return retriever -def get_neo4j_retriever(graph, document_names,chat_mode_settings, search_k=CHAT_SEARCH_KWARG_K, score_threshold=CHAT_SEARCH_KWARG_SCORE_THRESHOLD): +def get_neo4j_retriever(graph, document_names,chat_mode_settings, score_threshold=CHAT_SEARCH_KWARG_SCORE_THRESHOLD): try: - + neo_db = initialize_neo4j_vector(graph, chat_mode_settings) document_names= list(map(str.strip, json.loads(document_names))) - search_k = LOCAL_COMMUNITY_TOP_K if chat_mode_settings["mode"] == "entity search+vector" else CHAT_SEARCH_KWARG_K + search_k = chat_mode_settings["top_k"] retriever = create_retriever(neo_db, document_names,chat_mode_settings, search_k, score_threshold) return retriever except Exception as e: @@ -397,12 +408,13 @@ def process_chat_response(messages, history, question, model, graph, document_na try: llm, doc_retriever, model_version = setup_chat(model, graph, document_names, chat_mode_settings) - docs = retrieve_documents(doc_retriever, messages) + docs = retrieve_documents(doc_retriever, messages) + if docs: content, result, total_tokens = process_documents(docs, question, messages, llm, model, chat_mode_settings) else: content = "I couldn't find any relevant documents to answer your question." - result = {"sources": [], "chunkdetails": [], "entities": []} + result = {"sources": list(), "nodedetails": list(), "entities": list()} total_tokens = 0 ai_response = AIMessage(content=content) @@ -412,18 +424,18 @@ def process_chat_response(messages, history, question, model, graph, document_na summarization_thread.start() logging.info("Summarization thread started.") # summarize_and_log(history, messages, llm) - + return { "session_id": "", "message": content, "info": { "sources": result["sources"], "model": model_version, - "chunkdetails": result["chunkdetails"], + "nodedetails": result["nodedetails"], "total_tokens": total_tokens, "response_time": 0, "mode": chat_mode_settings["mode"], - "entities": result["entities"] + "entities": result["entities"], }, "user": "chatbot" } @@ -435,12 +447,12 @@ def process_chat_response(messages, history, question, model, graph, document_na "message": "Something went wrong", "info": { "sources": [], - "chunkdetails": [], + "nodedetails": [], "total_tokens": 0, "response_time": 0, "error": f"{type(e).__name__}: {str(e)}", "mode": chat_mode_settings["mode"], - "entities": [] + "entities": [], }, "user": "chatbot" } @@ -593,7 +605,7 @@ def create_neo4j_chat_message_history(graph, session_id, write_access=True): raise def get_chat_mode_settings(mode,settings_map=CHAT_MODE_CONFIG_MAP): - default_settings = settings_map["default"] + default_settings = settings_map[CHAT_DEFAULT_MODE] try: chat_mode_settings = settings_map.get(mode, default_settings) chat_mode_settings["mode"] = mode @@ -615,7 +627,7 @@ def QA_RAG(graph,model, question, document_names, session_id, mode, write_access user_question = HumanMessage(content=question) messages.append(user_question) - if mode == "graph": + if mode == CHAT_GRAPH_MODE: result = process_graph_response(model, graph, question, messages, history) else: chat_mode_settings = get_chat_mode_settings(mode=mode) diff --git a/backend/src/chunkid_entities.py b/backend/src/chunkid_entities.py index aa8d1d4ca..8bb9c2198 100644 --- a/backend/src/chunkid_entities.py +++ b/backend/src/chunkid_entities.py @@ -81,16 +81,16 @@ def process_chunk_data(chunk_data): except Exception as e: logging.error(f"chunkid_entities module: An error occurred while extracting the Chunk text from records: {e}") -def process_chunkids(driver, chunk_ids): +def process_chunkids(driver, chunk_ids, entities): """ Processes chunk IDs to retrieve chunk data. """ try: logging.info(f"Starting graph query process for chunk ids: {chunk_ids}") - chunk_ids_list = chunk_ids.split(",") - - records, summary, keys = driver.execute_query(CHUNK_QUERY, chunksIds=chunk_ids_list) + records, summary, keys = driver.execute_query(CHUNK_QUERY, chunksIds=chunk_ids,entityIds=entities["entityids"], relationshipIds=entities["relationshipids"]) result = process_records(records) + result["nodes"].extend(records[0]["nodes"]) + result["nodes"] = remove_duplicate_nodes(result["nodes"]) logging.info(f"Nodes and relationships are processed") result["chunk_data"] = process_chunk_data(records) @@ -118,13 +118,12 @@ def remove_duplicate_nodes(nodes,property="element_id"): return unique_nodes -def process_entityids(driver, chunk_ids): +def process_entityids(driver, entity_ids): """ Processes entity IDs to retrieve local community data. """ try: - logging.info(f"Starting graph query process for entity ids: {chunk_ids}") - entity_ids_list = chunk_ids.split(",") + logging.info(f"Starting graph query process for entity ids: {entity_ids}") query_body = LOCAL_COMMUNITY_SEARCH_QUERY.format( topChunks=LOCAL_COMMUNITY_TOP_CHUNKS, topCommunities=LOCAL_COMMUNITY_TOP_COMMUNITIES, @@ -132,65 +131,82 @@ def process_entityids(driver, chunk_ids): ) query = LOCAL_COMMUNITY_DETAILS_QUERY_PREFIX + query_body + LOCAL_COMMUNITY_DETAILS_QUERY_SUFFIX - records, summary, keys = driver.execute_query(query, entityIds=entity_ids_list) + records, summary, keys = driver.execute_query(query, entityIds=entity_ids) result = process_records(records) if records: result["nodes"].extend(records[0]["nodes"]) result["nodes"] = remove_duplicate_nodes(result["nodes"]) + logging.info(f"Nodes and relationships are processed") + result["chunk_data"] = records[0]["chunks"] result["community_data"] = records[0]["communities"] else: result["chunk_data"] = list() result["community_data"] = list() - logging.info(f"Query process completed successfully for chunk ids: {chunk_ids}") + logging.info(f"Query process completed successfully for chunk ids: {entity_ids}") return result except Exception as e: - logging.error(f"chunkid_entities module: Error processing entity ids: {chunk_ids}. Error: {e}") + logging.error(f"chunkid_entities module: Error processing entity ids: {entity_ids}. Error: {e}") raise -def get_entities_from_chunkids(uri, username, password, database ,chunk_ids,is_entity=False): - """ - Retrieve and process nodes and relationships from a graph database given a list of chunk IDs. +def process_communityids(driver, community_ids): + """Processes community IDs to retrieve community data.""" + try: + logging.info(f"Starting graph query process for community ids: {community_ids}") + query = GLOBAL_COMMUNITY_DETAILS_QUERY + records, summary, keys = driver.execute_query(query, communityids=community_ids) + + result = {"nodes": [], "relationships": [], "chunk_data": []} + result["community_data"] = records[0]["communities"] if records else [] - Parameters: - uri (str): The URI of the graph database. - username (str): The username for the database authentication. - password (str): The password for the database authentication. - chunk_ids (str): A comma-separated string of chunk IDs. + logging.info(f"Query process completed successfully for community ids: {community_ids}") + return result + except Exception as e: + logging.error(f"chunkid_entities module: Error processing community ids: {community_ids}. Error: {e}") + raise - Returns: - dict: A dictionary with 'nodes' and 'relationships' keys containing processed data, or an error message. - """ +def get_entities_from_chunkids(uri, username, password, database ,nodedetails,entities,mode): try: driver = get_graphDB_driver(uri, username, password,database) - if not is_entity: - if chunk_ids: - logging.info(f"chunkid_entities module: Starting for chunk ids : {chunk_ids}") - result = process_chunkids(driver,chunk_ids) + default_response = {"nodes": list(),"relationships": list(),"chunk_data": list(),"community_data": list(),} + + nodedetails = json.loads(nodedetails) + entities = json.loads(entities) + + if mode == CHAT_GLOBAL_VECTOR_FULLTEXT_MODE: + + if "communitydetails" in nodedetails and nodedetails["communitydetails"]: + community_ids = [item["id"] for item in nodedetails["communitydetails"]] + logging.info(f"chunkid_entities module: Starting for community ids: {community_ids}") + return process_communityids(driver, community_ids) + else: + logging.info("chunkid_entities module: No community ids are passed") + return default_response + + elif mode == CHAT_ENTITY_VECTOR_MODE: + + if "entitydetails" in nodedetails and nodedetails["entitydetails"]: + entity_ids = [item["id"] for item in nodedetails["entitydetails"]] + logging.info(f"chunkid_entities module: Starting for entity ids: {entity_ids}") + return process_entityids(driver, entity_ids) else: - logging.info(f"chunkid_entities module: No chunk ids are passed") - result = { - "nodes": [], - "relationships": [], - "chunk_data":[] - } - return result - if chunk_ids: - result = process_entityids(driver,chunk_ids) - logging.info(f"chunkid_entities module: Starting for entity ids : {chunk_ids}") + logging.info("chunkid_entities module: No entity ids are passed") + return default_response + else: - logging.info(f"chunkid_entities module: No entity ids are passed") - result = { - "nodes": [], - "relationships": [], - "chunk_data":[], - "community_data":[] - } - return result + + if "chunkdetails" in nodedetails and nodedetails["chunkdetails"]: + chunk_ids = [item["id"] for item in nodedetails["chunkdetails"]] + logging.info(f"chunkid_entities module: Starting for chunk ids: {chunk_ids}") + return process_chunkids(driver, chunk_ids, entities) + else: + logging.info("chunkid_entities module: No chunk ids are passed") + return default_response except Exception as e: logging.error(f"chunkid_entities module: An error occurred in get_entities_from_chunkids. Error: {str(e)}") - raise Exception(f"chunkid_entities module: An error occurred in get_entities_from_chunkids. Please check the logs for more details.") from e \ No newline at end of file + raise Exception(f"chunkid_entities module: An error occurred in get_entities_from_chunkids. Please check the logs for more details.") from e + diff --git a/backend/src/shared/constants.py b/backend/src/shared/constants.py index f76812553..834459fd1 100644 --- a/backend/src/shared/constants.py +++ b/backend/src/shared/constants.py @@ -22,82 +22,150 @@ GRAPH_QUERY = """ MATCH docs = (d:Document) WHERE d.fileName IN $document_names -WITH docs, d ORDER BY d.createdAt DESC -// fetch chunks for documents, currently with limit +WITH docs, d +ORDER BY d.createdAt DESC + +// Fetch chunks for documents, currently with limit CALL {{ WITH d - OPTIONAL MATCH chunks=(d)<-[:PART_OF|FIRST_CHUNK]-(c:Chunk) + OPTIONAL MATCH chunks = (d)<-[:PART_OF|FIRST_CHUNK]-(c:Chunk) RETURN c, chunks LIMIT {graph_chunk_limit} }} -WITH collect(distinct docs) as docs, collect(distinct chunks) as chunks, collect(distinct c) as selectedChunks -WITH docs, chunks, selectedChunks -// select relationships between selected chunks +WITH collect(distinct docs) AS docs, + collect(distinct chunks) AS chunks, + collect(distinct c) AS selectedChunks + +// Select relationships between selected chunks WITH *, -[ c in selectedChunks | [p=(c)-[:NEXT_CHUNK|SIMILAR]-(other) WHERE other IN selectedChunks | p]] as chunkRels + [c IN selectedChunks | + [p = (c)-[:NEXT_CHUNK|SIMILAR]-(other) + WHERE other IN selectedChunks | p]] AS chunkRels -// fetch entities and relationships between entities +// Fetch entities and relationships between entities CALL {{ WITH selectedChunks - UNWIND selectedChunks as c - - OPTIONAL MATCH entities=(c:Chunk)-[:HAS_ENTITY]->(e) - OPTIONAL MATCH entityRels=(e)--(e2:!Chunk) WHERE exists {{ + UNWIND selectedChunks AS c + OPTIONAL MATCH entities = (c:Chunk)-[:HAS_ENTITY]->(e) + OPTIONAL MATCH entityRels = (e)--(e2:!Chunk) + WHERE exists {{ (e2)<-[:HAS_ENTITY]-(other) WHERE other IN selectedChunks }} - RETURN entities , entityRels, collect(DISTINCT e) as entity + RETURN entities, entityRels, collect(DISTINCT e) AS entity }} -WITH docs,chunks,chunkRels, collect(entities) as entities, collect(entityRels) as entityRels, entity + +WITH docs, chunks, chunkRels, + collect(entities) AS entities, + collect(entityRels) AS entityRels, + entity WITH * CALL {{ - with entity - unwind entity as n - OPTIONAL MATCH community=(n:__Entity__)-[:IN_COMMUNITY]->(p:__Community__) - OPTIONAL MATCH parentcommunity=(p)-[:PARENT_COMMUNITY*]->(p2:__Community__) - return collect(community) as communities , collect(parentcommunity) as parentCommunities + WITH entity + UNWIND entity AS n + OPTIONAL MATCH community = (n:__Entity__)-[:IN_COMMUNITY]->(p:__Community__) + OPTIONAL MATCH parentcommunity = (p)-[:PARENT_COMMUNITY*]->(p2:__Community__) + RETURN collect(community) AS communities, + collect(parentcommunity) AS parentCommunities +}} + +WITH apoc.coll.flatten(docs + chunks + chunkRels + entities + entityRels + communities + parentCommunities, true) AS paths + +// Distinct nodes and relationships +CALL {{ + WITH paths + UNWIND paths AS path + UNWIND nodes(path) AS node + WITH distinct node + RETURN collect(node /* {{.*, labels:labels(node), elementId:elementId(node), embedding:null, text:null}} */) AS nodes }} -WITH apoc.coll.flatten(docs + chunks + chunkRels + entities + entityRels + communities + parentCommunities, true) as paths +CALL {{ + WITH paths + UNWIND paths AS path + UNWIND relationships(path) AS rel + RETURN collect(distinct rel) AS rels +}} -// distinct nodes and rels -CALL {{ WITH paths UNWIND paths AS path UNWIND nodes(path) as node WITH distinct node - RETURN collect(node /* {{.*, labels:labels(node), elementId:elementId(node), embedding:null, text:null}} */) AS nodes }} -CALL {{ WITH paths UNWIND paths AS path UNWIND relationships(path) as rel RETURN collect(distinct rel) AS rels }} RETURN nodes, rels """ CHUNK_QUERY = """ -match (chunk:Chunk) where chunk.id IN $chunksIds - +MATCH (chunk:Chunk) +WHERE chunk.id IN $chunksIds MATCH (chunk)-[:PART_OF]->(d:Document) -CALL {WITH chunk -MATCH (chunk)-[:HAS_ENTITY]->(e) -MATCH path=(e)(()-[rels:!HAS_ENTITY&!PART_OF]-()){0,2}(:!Chunk &! Document &! `__Community__`) -UNWIND rels as r -RETURN collect(distinct r) as rels -} -WITH d, collect(distinct chunk) as chunks, apoc.coll.toSet(apoc.coll.flatten(collect(rels))) as rels -RETURN d as doc, [chunk in chunks | chunk {.*, embedding:null}] as chunks, - [r in rels | {startNode:{element_id:elementId(startNode(r)), labels:labels(startNode(r)), properties:{id:startNode(r).id,description:startNode(r).description}}, - endNode:{element_id:elementId(endNode(r)), labels:labels(endNode(r)), properties:{id:endNode(r).id,description:endNode(r).description}}, - relationship: {type:type(r), element_id:elementId(r)}}] as entities + +WITH d, + collect(distinct chunk) AS chunks + +// Collect relationships and nodes +WITH d, chunks, + collect { + MATCH ()-[r]->() + WHERE elementId(r) IN $relationshipIds + RETURN r + } AS rels, + collect { + MATCH (e) + WHERE elementId(e) IN $entityIds + RETURN e + } AS nodes + +WITH d, + chunks, + apoc.coll.toSet(apoc.coll.flatten(rels)) AS rels, + nodes + +RETURN + d AS doc, + [chunk IN chunks | + chunk {.*, embedding: null} + ] AS chunks, + [ + node IN nodes | + { + element_id: elementId(node), + labels: labels(node), + properties: { + id: node.id, + description: node.description + } + } + ] AS nodes, + [ + r IN rels | + { + startNode: { + element_id: elementId(startNode(r)), + labels: labels(startNode(r)), + properties: { + id: startNode(r).id, + description: startNode(r).description + } + }, + endNode: { + element_id: elementId(endNode(r)), + labels: labels(endNode(r)), + properties: { + id: endNode(r).id, + description: endNode(r).description + } + }, + relationship: { + type: type(r), + element_id: elementId(r) + } + } + ] AS entities """ ## CHAT SETUP CHAT_MAX_TOKENS = 1000 -CHAT_SEARCH_KWARG_K = 10 CHAT_SEARCH_KWARG_SCORE_THRESHOLD = 0.5 CHAT_DOC_SPLIT_SIZE = 3000 CHAT_EMBEDDING_FILTER_SCORE_THRESHOLD = 0.10 -CHAT_TOKEN_CUT_OFF = { - ("openai-gpt-3.5",'azure_ai_gpt_35',"gemini-1.0-pro","gemini-1.5-pro","gemini-1.5-flash","groq-llama3",'groq_llama3_70b','anthropic_claude_3_5_sonnet','fireworks_llama_v3_70b','bedrock_claude_3_5_sonnet', ) : 4, - ("openai-gpt-4","diffbot" ,'azure_ai_gpt_4o',"openai-gpt-4o", "openai-gpt-4o-mini") : 28, - ("ollama_llama3") : 2 -} - CHAT_TOKEN_CUT_OFF = { ("openai-gpt-3.5",'azure_ai_gpt_35',"gemini-1.0-pro","gemini-1.5-pro", "gemini-1.5-flash","groq-llama3",'groq_llama3_70b','anthropic_claude_3_5_sonnet','fireworks_llama_v3_70b','bedrock_claude_3_5_sonnet', ) : 4, @@ -150,85 +218,146 @@ QUESTION_TRANSFORM_TEMPLATE = "Given the below conversation, generate a search query to look up in order to get information relevant to the conversation. Only respond with the query, nothing else." -## CHAT QUERIES +## CHAT QUERIES +VECTOR_SEARCH_TOP_K = 10 + VECTOR_SEARCH_QUERY = """ WITH node AS chunk, score MATCH (chunk)-[:PART_OF]->(d:Document) -WITH d, collect(distinct {chunk: chunk, score: score}) as chunks, avg(score) as avg_score +WITH d, + collect(distinct {chunk: chunk, score: score}) AS chunks, + avg(score) AS avg_score + WITH d, avg_score, - [c in chunks | c.chunk.text] as texts, - [c in chunks | {id: c.chunk.id, score: c.score}] as chunkdetails -WITH d, avg_score, chunkdetails, - apoc.text.join(texts, "\n----\n") as text -RETURN text, avg_score AS score, - {source: COALESCE(CASE WHEN d.url CONTAINS "None" THEN d.fileName ELSE d.url END, d.fileName), chunkdetails: chunkdetails} as metadata + [c IN chunks | c.chunk.text] AS texts, + [c IN chunks | {id: c.chunk.id, score: c.score}] AS chunkdetails + +WITH d, avg_score, chunkdetails, + apoc.text.join(texts, "\n----\n") AS text + +RETURN text, + avg_score AS score, + {source: COALESCE(CASE WHEN d.url CONTAINS "None" + THEN d.fileName + ELSE d.url + END, + d.fileName), + chunkdetails: chunkdetails} AS metadata """ +### Vector graph search VECTOR_GRAPH_SEARCH_ENTITY_LIMIT = 25 +VECTOR_GRAPH_SEARCH_EMBEDDING_MIN_MATCH = 0.3 +VECTOR_GRAPH_SEARCH_EMBEDDING_MAX_MATCH = 0.9 +VECTOR_GRAPH_SEARCH_ENTITY_LIMIT_MINMAX_CASE = 10 +VECTOR_GRAPH_SEARCH_ENTITY_LIMIT_MAX_CASE = 25 -VECTOR_GRAPH_SEARCH_QUERY = """ +VECTOR_GRAPH_SEARCH_QUERY_PREFIX = """ WITH node as chunk, score // find the document of the chunk MATCH (chunk)-[:PART_OF]->(d:Document) - // aggregate chunk-details -WITH d, collect(DISTINCT {{chunk: chunk, score: score}}) AS chunks, avg(score) as avg_score +WITH d, collect(DISTINCT {chunk: chunk, score: score}) AS chunks, avg(score) as avg_score // fetch entities -CALL {{ WITH chunks +CALL { WITH chunks UNWIND chunks as chunkScore WITH chunkScore.chunk as chunk -// entities connected to the chunk -// todo only return entities that are actually in the chunk, remember we connect all extracted entities to all chunks -// todo sort by relevancy (embeddding comparision?) cut off after X (e.g. 25) nodes? -OPTIONAL MATCH (chunk)-[:HAS_ENTITY]->(e) -WITH e, count(*) as numChunks -ORDER BY numChunks DESC LIMIT {no_of_entites} -// depending on match to query embedding either 1 or 2 step expansion -WITH CASE WHEN true // vector.similarity.cosine($embedding, e.embedding ) <= 0.95 -THEN -collect {{ OPTIONAL MATCH path=(e)(()-[rels:!HAS_ENTITY&!PART_OF]-()){{0,1}}(:!Chunk&!Document) RETURN path }} -ELSE -collect {{ OPTIONAL MATCH path=(e)(()-[rels:!HAS_ENTITY&!PART_OF]-()){{0,2}}(:!Chunk&!Document) RETURN path }} -END as paths, e -WITH apoc.coll.toSet(apoc.coll.flatten(collect(distinct paths))) as paths, collect(distinct e) as entities -// de-duplicate nodes and relationships across chunks -RETURN collect{{ unwind paths as p unwind relationships(p) as r return distinct r}} as rels, -collect{{ unwind paths as p unwind nodes(p) as n return distinct n}} as nodes, entities -}} +""" -// generate metadata and text components for chunks, nodes and relationships +VECTOR_GRAPH_SEARCH_ENTITY_QUERY = """ + OPTIONAL MATCH (chunk)-[:HAS_ENTITY]->(e) + WITH e, count(*) AS numChunks + ORDER BY numChunks DESC + LIMIT {no_of_entites} + + WITH + CASE + WHEN e.embedding IS NULL OR ({embedding_match_min} <= vector.similarity.cosine($embedding, e.embedding) AND vector.similarity.cosine($embedding, e.embedding) <= {embedding_match_max}) THEN + collect {{ + OPTIONAL MATCH path=(e)(()-[rels:!HAS_ENTITY&!PART_OF]-()){{0,1}}(:!Chunk&!Document&!__Community__) + RETURN path LIMIT {entity_limit_minmax_case} + }} + WHEN e.embedding IS NOT NULL AND vector.similarity.cosine($embedding, e.embedding) > {embedding_match_max} THEN + collect {{ + OPTIONAL MATCH path=(e)(()-[rels:!HAS_ENTITY&!PART_OF]-()){{0,2}}(:!Chunk&!Document&!__Community__) + RETURN path LIMIT {entity_limit_max_case} + }} + ELSE + collect {{ + MATCH path=(e) + RETURN path + }} + END AS paths, e +""" + +VECTOR_GRAPH_SEARCH_QUERY_SUFFIX = """ + WITH apoc.coll.toSet(apoc.coll.flatten(collect(DISTINCT paths))) AS paths, + collect(DISTINCT e) AS entities + + // De-duplicate nodes and relationships across chunks + RETURN + collect { + UNWIND paths AS p + UNWIND relationships(p) AS r + RETURN DISTINCT r + } AS rels, + collect { + UNWIND paths AS p + UNWIND nodes(p) AS n + RETURN DISTINCT n + } AS nodes, + entities +} + +// Generate metadata and text components for chunks, nodes, and relationships WITH d, avg_score, [c IN chunks | c.chunk.text] AS texts, - [c IN chunks | {{id: c.chunk.id, score: c.score}}] AS chunkdetails, - apoc.coll.sort([n in nodes | - -coalesce(apoc.coll.removeAll(labels(n),['__Entity__'])[0],"") +":"+ -n.id + (case when n.description is not null then " ("+ n.description+")" else "" end)]) as nodeTexts, - apoc.coll.sort([r in rels - // optional filter if we limit the node-set - // WHERE startNode(r) in nodes AND endNode(r) in nodes - | -coalesce(apoc.coll.removeAll(labels(startNode(r)),['__Entity__'])[0],"") +":"+ -startNode(r).id + -" " + type(r) + " " + -coalesce(apoc.coll.removeAll(labels(endNode(r)),['__Entity__'])[0],"") +":" + endNode(r).id -]) as relTexts -, entities -// combine texts into response-text - -WITH d, avg_score,chunkdetails, -"Text Content:\\n" + -apoc.text.join(texts,"\\n----\\n") + -"\\n----\\nEntities:\\n"+ -apoc.text.join(nodeTexts,"\\n") + -"\\n----\\nRelationships:\\n" + -apoc.text.join(relTexts,"\\n") - -as text,entities - -RETURN text, avg_score as score, {{length:size(text), source: COALESCE( CASE WHEN d.url CONTAINS "None" THEN d.fileName ELSE d.url END, d.fileName), chunkdetails: chunkdetails}} AS metadata + [c IN chunks | {id: c.chunk.id, score: c.score}] AS chunkdetails, + [n IN nodes | elementId(n)] AS entityIds, + [r IN rels | elementId(r)] AS relIds, + apoc.coll.sort([ + n IN nodes | + coalesce(apoc.coll.removeAll(labels(n), ['__Entity__'])[0], "") + ":" + + n.id + + (CASE WHEN n.description IS NOT NULL THEN " (" + n.description + ")" ELSE "" END) + ]) AS nodeTexts, + apoc.coll.sort([ + r IN rels | + coalesce(apoc.coll.removeAll(labels(startNode(r)), ['__Entity__'])[0], "") + ":" + + startNode(r).id + " " + type(r) + " " + + coalesce(apoc.coll.removeAll(labels(endNode(r)), ['__Entity__'])[0], "") + ":" + endNode(r).id + ]) AS relTexts, + entities + +// Combine texts into response text +WITH d, avg_score, chunkdetails, entityIds, relIds, + "Text Content:\n" + apoc.text.join(texts, "\n----\n") + + "\n----\nEntities:\n" + apoc.text.join(nodeTexts, "\n") + + "\n----\nRelationships:\n" + apoc.text.join(relTexts, "\n") AS text, + entities + +RETURN + text, + avg_score AS score, + { + length: size(text), + source: COALESCE(CASE WHEN d.url CONTAINS "None" THEN d.fileName ELSE d.url END, d.fileName), + chunkdetails: chunkdetails, + entities : { + entityids: entityIds, + relationshipids: relIds + } + } AS metadata """ +VECTOR_GRAPH_SEARCH_QUERY = VECTOR_GRAPH_SEARCH_QUERY_PREFIX+ VECTOR_GRAPH_SEARCH_ENTITY_QUERY.format( + no_of_entites=VECTOR_GRAPH_SEARCH_ENTITY_LIMIT, + embedding_match_min=VECTOR_GRAPH_SEARCH_EMBEDDING_MIN_MATCH, + embedding_match_max=VECTOR_GRAPH_SEARCH_EMBEDDING_MAX_MATCH, + entity_limit_minmax_case=VECTOR_GRAPH_SEARCH_ENTITY_LIMIT_MINMAX_CASE, + entity_limit_max_case=VECTOR_GRAPH_SEARCH_ENTITY_LIMIT_MAX_CASE +) + VECTOR_GRAPH_SEARCH_QUERY_SUFFIX + ### Local community search LOCAL_COMMUNITY_TOP_K = 10 LOCAL_COMMUNITY_TOP_CHUNKS = 3 @@ -392,45 +521,112 @@ ] AS entities """ +LOCAL_COMMUNITY_SEARCH_QUERY_FORMATTED = LOCAL_COMMUNITY_SEARCH_QUERY.format( + topChunks=LOCAL_COMMUNITY_TOP_CHUNKS, + topCommunities=LOCAL_COMMUNITY_TOP_COMMUNITIES, + topOutsideRels=LOCAL_COMMUNITY_TOP_OUTSIDE_RELS)+LOCAL_COMMUNITY_SEARCH_QUERY_SUFFIX + +GLOBAL_SEARCH_TOP_K = 10 + +GLOBAL_VECTOR_SEARCH_QUERY = """ +WITH collect(distinct {community: node, score: score}) AS communities, + avg(score) AS avg_score + +WITH avg_score, + [c IN communities | c.community.summary] AS texts, + [c IN communities | {id: elementId(c.community), score: c.score}] AS communityDetails + +WITH avg_score, communityDetails, + apoc.text.join(texts, "\n----\n") AS text + +RETURN text, + avg_score AS score, + {communitydetails: communityDetails} AS metadata +""" + + + +GLOBAL_COMMUNITY_DETAILS_QUERY = """ +MATCH (community:__Community__) +WHERE elementId(community) IN $communityids +WITH collect(distinct community) AS communities +RETURN [community IN communities | + community {.*, embedding: null, elementid: elementId(community)}] AS communities +""" + +## CHAT MODES + +CHAT_VECTOR_MODE = "vector" +CHAT_FULLTEXT_MODE = "fulltext" +CHAT_ENTITY_VECTOR_MODE = "entity search+vector" +CHAT_VECTOR_GRAPH_MODE = "graph+vector" +CHAT_VECTOR_GRAPH_FULLTEXT_MODE = "graph+vector+fulltext" +CHAT_GLOBAL_VECTOR_FULLTEXT_MODE = "global search+vector+fulltext" +CHAT_GRAPH_MODE = "graph" +CHAT_DEFAULT_MODE = "graph+vector+fulltext" + CHAT_MODE_CONFIG_MAP= { - "vector": { + CHAT_VECTOR_MODE : { "retrieval_query": VECTOR_SEARCH_QUERY, + "top_k": VECTOR_SEARCH_TOP_K, "index_name": "vector", "keyword_index": None, - "document_filter": True + "document_filter": True, + "node_label": "Chunk", + "embedding_node_property":"embedding", + "text_node_properties":["text"], + }, - "fulltext": { + CHAT_FULLTEXT_MODE : { "retrieval_query": VECTOR_SEARCH_QUERY, + "top_k": VECTOR_SEARCH_TOP_K, "index_name": "vector", "keyword_index": "keyword", - "document_filter": False + "document_filter": False, + "node_label": "Chunk", + "embedding_node_property":"embedding", + "text_node_properties":["text"], }, - "entity search+vector": { - "retrieval_query": LOCAL_COMMUNITY_SEARCH_QUERY.format(topChunks=LOCAL_COMMUNITY_TOP_CHUNKS, - topCommunities=LOCAL_COMMUNITY_TOP_COMMUNITIES, - topOutsideRels=LOCAL_COMMUNITY_TOP_OUTSIDE_RELS)+LOCAL_COMMUNITY_SEARCH_QUERY_SUFFIX, + CHAT_ENTITY_VECTOR_MODE : { + "retrieval_query": LOCAL_COMMUNITY_SEARCH_QUERY_FORMATTED, + "top_k": LOCAL_COMMUNITY_TOP_K, "index_name": "entity_vector", "keyword_index": None, - "document_filter": False + "document_filter": False, + "node_label": "__Entity__", + "embedding_node_property":"embedding", + "text_node_properties":["id"], }, - "graph+vector": { - "retrieval_query": VECTOR_GRAPH_SEARCH_QUERY.format(no_of_entites=VECTOR_GRAPH_SEARCH_ENTITY_LIMIT), + CHAT_VECTOR_GRAPH_MODE : { + "retrieval_query": VECTOR_GRAPH_SEARCH_QUERY, + "top_k": VECTOR_SEARCH_TOP_K, "index_name": "vector", "keyword_index": None, - "document_filter": True + "document_filter": True, + "node_label": "Chunk", + "embedding_node_property":"embedding", + "text_node_properties":["text"], }, - "graph+vector+fulltext": { - "retrieval_query": VECTOR_GRAPH_SEARCH_QUERY.format(no_of_entites=VECTOR_GRAPH_SEARCH_ENTITY_LIMIT), + CHAT_VECTOR_GRAPH_FULLTEXT_MODE : { + "retrieval_query": VECTOR_GRAPH_SEARCH_QUERY, + "top_k": VECTOR_SEARCH_TOP_K, "index_name": "vector", "keyword_index": "keyword", - "document_filter": False + "document_filter": False, + "node_label": "Chunk", + "embedding_node_property":"embedding", + "text_node_properties":["text"], + }, + CHAT_GLOBAL_VECTOR_FULLTEXT_MODE : { + "retrieval_query": GLOBAL_VECTOR_SEARCH_QUERY, + "top_k": GLOBAL_SEARCH_TOP_K, + "index_name": "community_vector", + "keyword_index": "community_keyword", + "document_filter": False, + "node_label": "__Community__", + "embedding_node_property":"embedding", + "text_node_properties":["summary"], }, - "default": { - "retrieval_query": VECTOR_SEARCH_QUERY, - "index_name": "vector", - "keyword_index": None, - "document_filter": True - } } YOUTUBE_CHUNK_SIZE_SECONDS = 60 diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index 74823520a..568868000 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -38,15 +38,24 @@ const ChatInfoModal: React.FC = ({ model, total_tokens, response_time, - chunk_ids, + nodeDetails, mode, cypher_query, graphonly_entities, error, + entities_ids }) => { const { breakpoints } = tokens; const isTablet = useMediaQuery(`(min-width:${breakpoints.xs}) and (max-width: ${breakpoints.lg})`); - const [activeTab, setActiveTab] = useState(error?.length ? 10 : mode === chatModeLables.graph ? 4 : 3); + const [activeTab, setActiveTab] = useState( + error?.length + ? 10 + : mode === chatModeLables.global_vector + ? 7 + : mode === chatModeLables.graph + ? 4 + : 3 + ); const [infoEntities, setInfoEntities] = useState([]); const [communities, setCommunities] = useState([]); const [loading, setLoading] = useState(false); @@ -86,11 +95,8 @@ const ChatInfoModal: React.FC = ({ (async () => { setLoading(true); try { - const response = await chunkEntitiesAPI( - userCredentials as UserCredentials, - chunk_ids.map((c) => c.id).join(','), - userCredentials?.database, - mode === chatModeLables.entity_vector + const response = await chunkEntitiesAPI(userCredentials as UserCredentials, userCredentials?.database, nodeDetails, entities_ids, + mode, ); if (response.data.status === 'Failure') { throw new Error(response.data.error); @@ -123,17 +129,27 @@ const ChatInfoModal: React.FC = ({ }) ); setRelationships(relationshipsData ?? []); - setCommunities(communitiesData ?? []); + setCommunities(communitiesData.map((community: any) => { + const communityScore = nodeDetails?.communitydetails?.find((c: any) => + c.id === community.element_id); + return { + ...community, + score: communityScore?.score || 1 + }; + }) + .sort((a: any, b: any) => b.score - a.score) + ); + setChunks( chunksData .map((chunk: any) => { - const chunkScore = chunk_ids.find((chunkdetail) => chunkdetail.id === chunk.id); - return ( - { - ...chunk, - score: chunkScore?.score, - } ?? [] - ); + const chunkScore = nodeDetails?.chunkdetails?.find((c: any) => + c.id + === chunk.id); + return { + ...chunk, + score: chunkScore?.score + }; }) .sort((a: any, b: any) => b.score - a.score) ); @@ -147,7 +163,7 @@ const ChatInfoModal: React.FC = ({ () => { setcopiedText(false); }; - }, [chunk_ids, mode, error]); + }, [nodeDetails, mode, error]); const onChangeTabs = (tabId: number) => { setActiveTab(tabId); @@ -175,22 +191,33 @@ const ChatInfoModal: React.FC = ({ {error} ) : ( - {mode != chatModeLables.graph ? Sources used : <>} - {mode != chatModeLables.graph ? Chunks : <>} - {mode === chatModeLables.graph_vector || - mode === chatModeLables.graph || - mode === chatModeLables.graph_vector_fulltext || - mode === chatModeLables.entity_vector ? ( - Top Entities used - ) : ( - <> - )} - {mode === chatModeLables.graph && cypher_query?.trim()?.length ? ( - Generated Cypher Query + {mode === chatModeLables.global_vector ? ( + // Only show the Communities tab if mode is global + Communities ) : ( - <> + <> + {mode != chatModeLables.graph ? Sources used : <>} + {mode != chatModeLables.graph ? Chunks : <>} + {mode === chatModeLables.graph_vector || + mode === chatModeLables.graph || + mode === chatModeLables.graph_vector_fulltext || + mode === chatModeLables.entity_vector ? ( + Top Entities used + ) : ( + <> + )} + {mode === chatModeLables.graph && cypher_query?.trim()?.length ? ( + Generated Cypher Query + ) : ( + <> + )} + {mode === chatModeLables.entity_vector ? ( + Communities + ) : ( + <> + )} + )} - {mode === chatModeLables.entity_vector ? Communities : <>} )} @@ -217,7 +244,7 @@ const ChatInfoModal: React.FC = ({ className='min-h-40' /> - {mode === chatModeLables.entity_vector ? ( + {mode === chatModeLables.entity_vector || mode === chatModeLables.global_vector ? ( diff --git a/frontend/src/components/ChatBot/ChatModeToggle.tsx b/frontend/src/components/ChatBot/ChatModeToggle.tsx index 187c37178..b3d493236 100644 --- a/frontend/src/components/ChatBot/ChatModeToggle.tsx +++ b/frontend/src/components/ChatBot/ChatModeToggle.tsx @@ -8,7 +8,7 @@ import { capitalizeWithPlus } from '../../utils/Utils'; import { useCredentials } from '../../context/UserCredentials'; export default function ChatModeToggle({ menuAnchor, - closeHandler = () => {}, + closeHandler = () => { }, open, anchorPortal = true, disableBackdrop = false, @@ -20,30 +20,35 @@ export default function ChatModeToggle({ disableBackdrop?: boolean; }) { const { setchatMode, chatMode, postProcessingTasks, selectedRows } = useFileContext(); - const isCommunityAllowed = postProcessingTasks.includes('create_communities'); + const isCommunityAllowed = postProcessingTasks.includes('enable_communities'); const { isGdsActive } = useCredentials(); useEffect(() => { - if (selectedRows.length !== 0) { - setchatMode(chatModeLables.graph_vector); - } else { - setchatMode(chatModeLables.graph_vector_fulltext); + // If rows are selected, the mode is valid (either vector or graph+vector) + if (selectedRows.length > 0) { + if (!(chatMode === chatModeLables.vector || chatMode === chatModeLables.graph_vector)) { + setchatMode(chatModeLables.graph_vector); + } } - }, [selectedRows]); - + }, [selectedRows.length, chatMode, setchatMode]); const memoizedChatModes = useMemo(() => { return isGdsActive && isCommunityAllowed ? chatModes - : chatModes?.filter((m) => !m.mode.includes(chatModeLables.entity_vector)); + : chatModes?.filter( + (m) => + !m.mode.includes(chatModeLables.entity_vector) && + !m.mode.includes(chatModeLables.global_vector) + ); }, [isGdsActive, isCommunityAllowed]); const menuItems = useMemo(() => { return memoizedChatModes?.map((m) => { const isDisabled = Boolean( - selectedRows.length && !(m.mode === chatModeLables.vector || m.mode === chatModeLables.graph_vector) + selectedRows.length && + !(m.mode === chatModeLables.vector || m.mode === chatModeLables.graph_vector) ); const handleModeChange = () => { if (isDisabled) { - setchatMode(chatModeLables.graph_vector); + setchatMode(chatModeLables.graph_vector); } else { setchatMode(m.mode); } @@ -52,11 +57,11 @@ export default function ChatModeToggle({ return { title: (
    - + {m.mode.includes('+') ? capitalizeWithPlus(m.mode) : capitalize(m.mode)}
    - {m.description} + {m.description}
    ), @@ -66,12 +71,12 @@ export default function ChatModeToggle({ {chatMode === m.mode && ( <> - {chatModeLables.selected} + {chatModeLables.selected} )} {isDisabled && ( <> - {chatModeLables.unavailableChatMode} + {chatModeLables.unavailableChatMode} )} @@ -82,10 +87,9 @@ export default function ChatModeToggle({ useEffect(() => { if (!selectedRows.length && !chatMode) { - setchatMode(chatMode); + setchatMode(chatModeLables.graph_vector_fulltext); } - }, [setchatMode, selectedRows, chatMode]); - + }, [setchatMode, selectedRows.length, chatMode]); return ( = (props) => { const [sourcesModal, setSourcesModal] = useState([]); const [modelModal, setModelModal] = useState(''); const [responseTime, setResponseTime] = useState(0); - const [chunkModal, setChunkModal] = useState([]); const [tokensUsed, setTokensUsed] = useState(0); const [cypherQuery, setcypherQuery] = useState(''); const [copyMessageId, setCopyMessageId] = useState(null); const [chatsMode, setChatsMode] = useState(chatModeLables.graph_vector_fulltext); const [graphEntitites, setgraphEntitites] = useState<[]>([]); const [messageError, setmessageError] = useState(''); + const [entitiesModal, setEntitiesModal] = useState([]); + const [nodeDetailsModal, setNodeDetailsModal] = useState({}); const [value, copy] = useCopyToClipboard(); const { speak, cancel } = useSpeechSynthesis({ @@ -56,16 +57,10 @@ const Chatbot: FC = (props) => { setListMessages((msgs) => msgs.map((msg) => ({ ...msg, speaking: false }))); }, }); - let selectedFileNames: CustomFile[] = []; - for (let index = 0; index < selectedRows.length; index++) { - const id = selectedRows[index]; - for (let index = 0; index < filesData.length; index++) { - const f = filesData[index]; - if (f.id === id) { - selectedFileNames.push(f); - } - } - } + + let selectedFileNames: CustomFile[] = filesData.filter(f => + selectedRows.includes(f.id) && ['Completed'].includes(f.status) + ); const handleInputChange = (e: React.ChangeEvent) => { setInputMessage(e.target.value); @@ -82,7 +77,6 @@ const Chatbot: FC = (props) => { reply: string; sources?: string[]; model?: string; - chunk_ids?: chunk[]; total_tokens?: number; response_time?: number; speaking?: boolean; @@ -91,7 +85,8 @@ const Chatbot: FC = (props) => { cypher_query?: string; graphonly_entities?: []; error?: string; - entitiysearchonly_entities?: chunk[]; + entitiysearchonly_entities?: string[]; + nodeDetails?: nodeDetailsProps; }, index = 0 ) => { @@ -113,7 +108,6 @@ const Chatbot: FC = (props) => { isLoading: true, sources: response?.sources, model: response?.model, - chunks: response?.chunk_ids, total_tokens: response.total_tokens, response_time: response?.response_time, speaking: false, @@ -123,6 +117,7 @@ const Chatbot: FC = (props) => { graphonly_entities: response?.graphonly_entities, error: response.error, entitiysearchonly_entities: response.entitiysearchonly_entities, + nodeDetails: response?.nodeDetails }, ]); } else { @@ -136,7 +131,6 @@ const Chatbot: FC = (props) => { lastmsg.isLoading = false; lastmsg.sources = response?.sources; lastmsg.model = response?.model; - lastmsg.chunk_ids = response?.chunk_ids; lastmsg.total_tokens = response?.total_tokens; lastmsg.response_time = response?.response_time; lastmsg.speaking = false; @@ -146,6 +140,7 @@ const Chatbot: FC = (props) => { lastmsg.graphonly_entities = response.graphonly_entities; lastmsg.error = response.error; lastmsg.entities = response.entitiysearchonly_entities; + lastmsg.nodeDetails = response?.nodeDetails; return msgs.map((msg, index) => { if (index === msgs.length - 1) { return lastmsg; @@ -172,7 +167,7 @@ const Chatbot: FC = (props) => { let chatbotReply; let chatSources; let chatModel; - let chatChunks; + let chatnodedetails; let chatTimeTaken; let chatTokensUsed; let chatingMode; @@ -180,6 +175,7 @@ const Chatbot: FC = (props) => { let graphonly_entities; let error; let entitiysearchonly_entities; + let chatEntities; const datetime = `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`; const userMessage = { id: Date.now(), user: 'user', message: inputMessage, datetime: datetime, mode: chatMode }; setListMessages([...listMessages, userMessage]); @@ -198,7 +194,7 @@ const Chatbot: FC = (props) => { chatbotReply = chatresponse?.data?.data?.message; chatSources = chatresponse?.data?.data?.info.sources; chatModel = chatresponse?.data?.data?.info.model; - chatChunks = chatresponse?.data?.data?.info.chunkdetails; + chatnodedetails = chatresponse?.data?.data?.info.nodedetails; chatTokensUsed = chatresponse?.data?.data?.info.total_tokens; chatTimeTaken = chatresponse?.data?.data?.info.response_time; chatingMode = chatresponse?.data?.data?.info?.mode; @@ -206,11 +202,11 @@ const Chatbot: FC = (props) => { graphonly_entities = chatresponse?.data.data.info.context ?? []; entitiysearchonly_entities = chatresponse?.data.data.info.entities; error = chatresponse.data.data.info.error ?? ''; + chatEntities = chatresponse.data.data.info.entities; const finalbotReply = { reply: chatbotReply, sources: chatSources, model: chatModel, - chunk_ids: chatChunks, total_tokens: chatTokensUsed, response_time: chatTimeTaken, speaking: false, @@ -220,6 +216,8 @@ const Chatbot: FC = (props) => { graphonly_entities, error, entitiysearchonly_entities, + chatEntities, + nodeDetails: chatnodedetails }; simulateTypingEffect(finalbotReply); } catch (error) { @@ -324,9 +322,8 @@ const Chatbot: FC = (props) => { @@ -338,11 +335,10 @@ const Chatbot: FC = (props) => { } >
    {chat.message}
    @@ -366,15 +362,14 @@ const Chatbot: FC = (props) => { setModelModal(chat.model ?? ''); setSourcesModal(chat.sources ?? []); setResponseTime(chat.response_time ?? 0); - setChunkModal( - chat.mode === 'entity search+vector' ? chat.entities ?? [] : chat.chunk_ids ?? [] - ); setTokensUsed(chat.total_tokens ?? 0); setcypherQuery(chat.cypher_query ?? ''); setShowInfoModal(true); setChatsMode(chat.mode ?? ''); setgraphEntitites(chat.graphonly_entities ?? []); + setEntitiesModal(chat.entities ?? []); setmessageError(chat.error ?? ''); + setNodeDetailsModal(chat.nodeDetails ?? {}) }} > {' '} @@ -428,9 +423,8 @@ const Chatbot: FC = (props) => {
    = (props) => { disabled={loading || !connectionStatus} size='medium' > - {buttonCaptions.ask} {selectedRows != undefined && selectedRows.length > 0 && `(${selectedRows.length})`} + {buttonCaptions.ask} {selectedFileNames != undefined && selectedFileNames.length > 0 && `(${selectedFileNames.length})`}
    @@ -473,13 +467,14 @@ const Chatbot: FC = (props) => { diff --git a/frontend/src/components/ChatBot/Communities.tsx b/frontend/src/components/ChatBot/Communities.tsx index 9b530fd0f..11869d3d4 100644 --- a/frontend/src/components/ChatBot/Communities.tsx +++ b/frontend/src/components/ChatBot/Communities.tsx @@ -4,6 +4,7 @@ import ReactMarkdown from 'react-markdown'; import { CommunitiesProps } from '../../types'; const CommunitiesInfo: FC = ({ loading, communities }) => { + console.log('communities', communities); return ( <> {loading ? ( @@ -20,6 +21,10 @@ const CommunitiesInfo: FC = ({ loading, communities }) => { ID : {community.id}
    + + Score : + {community.score} + {community.summary}
  • diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 0995426c1..3f7564461 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -33,6 +33,7 @@ import DatabaseStatusIcon from './UI/DatabaseStatusIcon'; import RetryConfirmationDialog from './Popups/RetryConfirmation/Index'; import retry from '../services/retry'; import { showErrorToast, showNormalToast, showSuccessToast } from '../utils/toasts'; +import { useMessageContext } from '../context/UserMessages'; const ConnectionModal = lazy(() => import('./Popups/ConnectionModal/ConnectionModal')); const ConfirmationDialog = lazy(() => import('./Popups/LargeFilePopUp/ConfirmationDialog')); @@ -79,7 +80,7 @@ const Content: React.FC = ({ alertType: 'neutral', alertMessage: '', }); - + const { setClearHistoryData } = useMessageContext(); const { filesData, setFilesData, @@ -94,6 +95,7 @@ const Content: React.FC = ({ queue, processedCount, setProcessedCount, + setPostProcessingVal } = useFileContext(); const [viewPoint, setViewPoint] = useState<'tableView' | 'showGraphView' | 'chatInfoView'>('tableView'); const [showDeletePopUp, setshowDeletePopUp] = useState(false); @@ -160,7 +162,7 @@ const Content: React.FC = ({ (async () => { showNormalToast('Some Q&A functionality will only be available afterwards.'); await postProcessing(userCredentials as UserCredentials, postProcessingTasks); - showSuccessToast('All Q&A functionality is available now.'); + showSuccessToast('All Q&A functionality is available now.'); })(); } }, [processedCount, userCredentials, queue]); @@ -510,9 +512,8 @@ const Content: React.FC = ({ const handleOpenGraphClick = () => { const bloomUrl = process.env.VITE_BLOOM_URL; const uriCoded = userCredentials?.uri.replace(/:\d+$/, ''); - const connectURL = `${uriCoded?.split('//')[0]}//${userCredentials?.userName}@${uriCoded?.split('//')[1]}:${ - userCredentials?.port ?? '7687' - }`; + const connectURL = `${uriCoded?.split('//')[0]}//${userCredentials?.userName}@${uriCoded?.split('//')[1]}:${userCredentials?.port ?? '7687' + }`; const encodedURL = encodeURIComponent(connectURL); const replacedUrl = bloomUrl?.replace('{CONNECT_URL}', encodedURL); window.open(replacedUrl, '_blank'); @@ -522,10 +523,10 @@ const Content: React.FC = ({ isLeftExpanded && isRightExpanded ? 'contentWithExpansion' : isRightExpanded - ? 'contentWithChatBot' - : !isLeftExpanded && !isRightExpanded - ? 'w-[calc(100%-128px)]' - : 'contentWithDropzoneExpansion'; + ? 'contentWithChatBot' + : !isLeftExpanded && !isRightExpanded + ? 'w-[calc(100%-128px)]' + : 'contentWithDropzoneExpansion'; const handleGraphView = () => { setOpenGraphView(true); @@ -540,6 +541,7 @@ const Content: React.FC = ({ setUserCredentials({ uri: '', password: '', userName: '', database: '' }); setSelectedNodes([]); setSelectedRels([]); + setClearHistoryData(true); }; const retryHandler = async (filename: string, retryoption: string) => { @@ -555,12 +557,12 @@ const Content: React.FC = ({ return prev.map((f) => { return f.name === filename ? { - ...f, - status: 'Reprocess', - processingProgress: isStartFromBegining ? 0 : f.processingProgress, - NodesCount: isStartFromBegining ? 0 : f.NodesCount, - relationshipCount: isStartFromBegining ? 0 : f.relationshipCount, - } + ...f, + status: 'Reprocess', + processingProgress: isStartFromBegining ? 0 : f.processingProgress, + NodesCount: isStartFromBegining ? 0 : f.NodesCount, + relationshipCount: isStartFromBegining ? 0 : f.relationshipCount, + } : f; }); }); @@ -849,9 +851,8 @@ const Content: React.FC = ({ handleGenerateGraph={processWaitingFilesOnRefresh} > diff --git a/frontend/src/components/Graph/CheckboxSelection.tsx b/frontend/src/components/Graph/CheckboxSelection.tsx index b335a4324..738a1dd01 100644 --- a/frontend/src/components/Graph/CheckboxSelection.tsx +++ b/frontend/src/components/Graph/CheckboxSelection.tsx @@ -3,21 +3,23 @@ import React from 'react'; import { CheckboxSectionProps } from '../../types'; import { graphLabels } from '../../utils/Constants'; -const CheckboxSelection: React.FC = ({ graphType, loading, handleChange, isgds }) => ( +const CheckboxSelection: React.FC = ({ graphType, loading, handleChange, isgds, isDocChunk, isEntity }) => (
    - handleChange('DocumentChunk')} - /> - handleChange('Entities')} - /> + />)} + {isEntity && ( + handleChange('Entities')} + /> + )} {isgds && ( = ({ graphType.includes('DocumentChunk') && graphType.includes('Entities') ? queryMap.DocChunkEntities : graphType.includes('DocumentChunk') - ? queryMap.DocChunks - : graphType.includes('Entities') - ? queryMap.Entities - : ''; + ? queryMap.DocChunks + : graphType.includes('Entities') + ? queryMap.Entities + : ''; // fit graph to original position const handleZoomToFit = () => { @@ -136,10 +136,10 @@ const GraphViewModal: React.FunctionComponent = ({ const nodeRelationshipData = viewPoint === graphLabels.showGraphView ? await graphQueryAPI( - userCredentials as UserCredentials, - graphQuery, - selectedRows?.map((f) => f.name) - ) + userCredentials as UserCredentials, + graphQuery, + selectedRows?.map((f) => f.name) + ) : await graphQueryAPI(userCredentials as UserCredentials, graphQuery, [inspectedName ?? '']); return nodeRelationshipData; } catch (error: any) { @@ -152,9 +152,11 @@ const GraphViewModal: React.FunctionComponent = ({ try { const result = await fetchData(); if (result && result.data.data.nodes.length > 0) { - const neoNodes = result.data.data.nodes.map((f: Node) => f); - const neoRels = result.data.data.relationships.map((f: Relationship) => f); + const neoNodes = result.data.data.nodes.map((f: Node) => f).filter((node: ExtendedNode) => node.labels.length === 1); + const nodeIds = new Set(neoNodes.map((node:any) => node.element_id)); + const neoRels = result.data.data.relationships.map((f: Relationship) => f).filter((rel: any) => nodeIds.has(rel.end_node_element_id) && nodeIds.has(rel.start_node_element_id)); const { finalNodes, finalRels, schemeVal } = processGraphData(neoNodes, neoRels); + if (mode === 'refreshMode') { initGraph(graphType, finalNodes, finalRels, schemeVal); } else { @@ -246,8 +248,8 @@ const GraphViewModal: React.FunctionComponent = ({ match && viewPoint === graphLabels.showGraphView ? 100 : match && viewPoint !== graphLabels.showGraphView - ? 50 - : graphLabels.nodeSize, + ? 50 + : graphLabels.nodeSize, }; }); // deactivating any active relationships @@ -356,8 +358,8 @@ const GraphViewModal: React.FunctionComponent = ({ isActive && viewPoint === graphLabels.showGraphView ? 100 : isActive && viewPoint !== graphLabels.showGraphView - ? 50 - : graphLabels.nodeSize, + ? 50 + : graphLabels.nodeSize, }; }); // deactivating any active relationships @@ -421,7 +423,7 @@ const GraphViewModal: React.FunctionComponent = ({ graphType={graphType} loading={loading} handleChange={handleCheckboxChange} - isgds={allNodes.some((n) => n.labels.includes('__Community__'))} + {...getCheckboxConditions(allNodes)} /> )} diff --git a/frontend/src/components/Layout/PageLayout.tsx b/frontend/src/components/Layout/PageLayout.tsx index 07d795484..48e94c023 100644 --- a/frontend/src/components/Layout/PageLayout.tsx +++ b/frontend/src/components/Layout/PageLayout.tsx @@ -27,7 +27,6 @@ export default function PageLayoutNew({ const [isRightExpanded, setIsRightExpanded] = useState(Boolean(largedesktops)); const [showChatBot, setShowChatBot] = useState(false); const [showDrawerChatbot, setShowDrawerChatbot] = useState(true); - const [clearHistoryData, setClearHistoryData] = useState(false); const [showEnhancementDialog, toggleEnhancementDialog] = useReducer((s) => !s, false); const [shows3Modal, toggleS3Modal] = useReducer((s) => !s, false); const [showGCSModal, toggleGCSModal] = useReducer((s) => !s, false); @@ -48,7 +47,7 @@ export default function PageLayoutNew({ } }; - const { messages } = useMessageContext(); + const { messages, setClearHistoryData, clearHistoryData } = useMessageContext(); const { isSchema, setIsSchema, setShowTextFromSchemaDialog, showTextFromSchemaDialog } = useFileContext(); const deleteOnClick = async () => { diff --git a/frontend/src/components/Layout/SideNav.tsx b/frontend/src/components/Layout/SideNav.tsx index ee3ef510b..526150db4 100644 --- a/frontend/src/components/Layout/SideNav.tsx +++ b/frontend/src/components/Layout/SideNav.tsx @@ -203,7 +203,6 @@ const SideNav: React.FC = ({ {!isChatModalOpen && ( { setchatModeAnchor(e.currentTarget); setshowChatMode(true); diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/index.tsx index 28114ced7..b48b6c6a6 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/index.tsx @@ -20,7 +20,7 @@ export default function PostProcessingCheckList() { {POST_PROCESSING_JOBS.map((job, idx) => { - const isCreateCommunities = job.title === 'create_communities'; + const isCreateCommunities = job.title === 'enable_communities'; return ( = ({ children }) = const [messages, setMessages] = useState([ { ...chatbotmessages.listMessages[1], datetime: getDateTime() }, ]); + const [clearHistoryData, setClearHistoryData] = useState(false); const value: MessageContextType = { messages, setMessages, + clearHistoryData, + setClearHistoryData }; return {children}; }; diff --git a/frontend/src/context/UsersFiles.tsx b/frontend/src/context/UsersFiles.tsx index fbab1b719..7ff7e28c4 100644 --- a/frontend/src/context/UsersFiles.tsx +++ b/frontend/src/context/UsersFiles.tsx @@ -1,44 +1,9 @@ -import { createContext, useContext, useState, Dispatch, SetStateAction, FC, useEffect } from 'react'; -import { CustomFile, FileContextProviderProps, OptionType } from '../types'; +import { createContext, useContext, useState, FC, useEffect } from 'react'; +import { CustomFile, FileContextProviderProps, FileContextType, OptionType, showTextFromSchemaDialogType } from '../types'; import { chatModeLables, defaultLLM } from '../utils/Constants'; import { useCredentials } from './UserCredentials'; import Queue from '../utils/Queue'; -interface showTextFromSchemaDialogType { - triggeredFrom: string; - show: boolean; -} -interface FileContextType { - files: (File | null)[] | []; - filesData: CustomFile[] | []; - setFiles: Dispatch>; - setFilesData: Dispatch>; - model: string; - setModel: Dispatch>; - graphType: string; - setGraphType: Dispatch>; - selectedNodes: readonly OptionType[]; - setSelectedNodes: Dispatch>; - selectedRels: readonly OptionType[]; - setSelectedRels: Dispatch>; - rowSelection: Record; - setRowSelection: React.Dispatch>>; - selectedRows: string[]; - setSelectedRows: React.Dispatch>; - selectedSchemas: readonly OptionType[]; - setSelectedSchemas: Dispatch>; - chatMode: string; - setchatMode: Dispatch>; - isSchema: boolean; - setIsSchema: React.Dispatch>; - showTextFromSchemaDialog: showTextFromSchemaDialogType; - setShowTextFromSchemaDialog: React.Dispatch>; - postProcessingTasks: string[]; - setPostProcessingTasks: React.Dispatch>; - queue: Queue; - setQueue: Dispatch>; - processedCount: number; - setProcessedCount: Dispatch>; -} + const FileContext = createContext(undefined); const FileContextProvider: FC = ({ children }) => { @@ -68,9 +33,11 @@ const FileContextProvider: FC = ({ children }) => { 'materialize_text_chunk_similarities', 'enable_hybrid_search_and_fulltext_search_in_bloom', 'materialize_entity_similarities', - 'create_communities', + 'enable_communities', ]); const [processedCount, setProcessedCount] = useState(0); + const [postProcessingVal, setPostProcessingVal] = useState(false); + useEffect(() => { if (selectedNodeLabelstr != null) { const selectedNodeLabel = JSON.parse(selectedNodeLabelstr); @@ -117,6 +84,8 @@ const FileContextProvider: FC = ({ children }) => { setQueue, processedCount, setProcessedCount, + postProcessingVal, + setPostProcessingVal }; return {children}; }; diff --git a/frontend/src/services/ChunkEntitiesInfo.ts b/frontend/src/services/ChunkEntitiesInfo.ts index f69ddd3aa..39d9f8c2e 100644 --- a/frontend/src/services/ChunkEntitiesInfo.ts +++ b/frontend/src/services/ChunkEntitiesInfo.ts @@ -1,20 +1,22 @@ -import { ChatInfo_APIResponse, UserCredentials } from '../types'; +import { ChatInfo_APIResponse, nodeDetailsProps, UserCredentials } from '../types'; import api from '../API/Index'; const chunkEntitiesAPI = async ( userCredentials: UserCredentials, - chunk_ids: string, database: string = 'neo4j', - is_entity: boolean = false + nodeDetails: (nodeDetailsProps), + entities:(string)[], + mode: string, ) => { try { const formData = new FormData(); formData.append('uri', userCredentials?.uri ?? ''); formData.append('userName', userCredentials?.userName ?? ''); formData.append('password', userCredentials?.password ?? ''); - formData.append('chunk_ids', chunk_ids); formData.append('database', database); - formData.append('is_entity', String(is_entity)); + formData.append('nodedetails', JSON.stringify(nodeDetails)); + formData.append('entities', JSON.stringify(entities)); + formData.append('mode', mode); const response: ChatInfo_APIResponse = await api.post(`/chunk_entities`, formData, { headers: { diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 10f16e4d6..b280cc5d6 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -5,6 +5,7 @@ import { OverridableStringUnion } from '@mui/types'; import type { Node, Relationship } from '@neo4j-nvl/base'; import { NonOAuthError } from '@react-oauth/google'; import { BannerType } from '@neo4j-ndl/react'; +import Queue from './utils/Queue'; export interface CustomFileBase extends Partial { processing: number | string; @@ -201,7 +202,7 @@ export interface Source { source_name: string; start_time?: string; } -export interface chunk { +export interface ChunkDetail { id: string; score: number; } @@ -215,7 +216,8 @@ export interface Messages { model?: string; isLoading?: boolean; response_time?: number; - chunk_ids?: chunk[]; + nodeDetails?: nodeDetailsProps; + chunk_ids?: string[]; total_tokens?: number; speaking?: boolean; copying?: boolean; @@ -223,7 +225,7 @@ export interface Messages { cypher_query?: string; graphonly_entities?: []; error?: string; - entities?: chunk[]; + entities?: string[]; } export type ChatbotProps = { @@ -234,7 +236,7 @@ export type ChatbotProps = { isFullScreen?: boolean; connectionStatus: boolean; }; -export interface WikipediaModalTypes extends Omit {} +export interface WikipediaModalTypes extends Omit { } export interface GraphViewModalProps { open: boolean; @@ -257,6 +259,8 @@ export interface CheckboxSectionProps { loading: boolean; handleChange: (graph: GraphType) => void; isgds: boolean; + isDocChunk: boolean; + isEntity: boolean; } export interface fileName { @@ -414,12 +418,13 @@ export interface chatInfoMessage extends Partial { sources: string[]; model: string; response_time: number; - chunk_ids: chunk[]; total_tokens: number; mode: string; cypher_query?: string; graphonly_entities: []; error: string; + entities_ids: string[]; + nodeDetails: nodeDetailsProps; } export interface eventResponsetypes extends Omit { @@ -471,6 +476,7 @@ export type Community = { weight: number; level: number; community_rank: number; + score?: number; }; export type GroupedEntity = { texts: Set; @@ -639,6 +645,8 @@ export interface ContextProps { export interface MessageContextType { messages: Messages[] | []; setMessages: Dispatch>; + clearHistoryData: boolean; + setClearHistoryData: Dispatch> } export interface DatabaseStatusProps { @@ -670,3 +678,63 @@ export type CommunitiesProps = { loading: boolean; communities: Community[]; }; + +export interface entity { + id: string; + score: number; +}; + +export interface community { + id: string; + score: number; +} + +export interface nodeDetailsProps { + chunkdetails?: ChunkDetail[], + entitydetails?: entity[], + communitydetails?: community[] +} + +export type entityProps = { + entityids: [], + relationshipids: [] +} + +export interface showTextFromSchemaDialogType { + triggeredFrom: string; + show: boolean; +} +export interface FileContextType { + files: (File | null)[] | []; + filesData: CustomFile[] | []; + setFiles: Dispatch>; + setFilesData: Dispatch>; + model: string; + setModel: Dispatch>; + graphType: string; + setGraphType: Dispatch>; + selectedNodes: readonly OptionType[]; + setSelectedNodes: Dispatch>; + selectedRels: readonly OptionType[]; + setSelectedRels: Dispatch>; + rowSelection: Record; + setRowSelection: React.Dispatch>>; + selectedRows: string[]; + setSelectedRows: React.Dispatch>; + selectedSchemas: readonly OptionType[]; + setSelectedSchemas: Dispatch>; + chatMode: string; + setchatMode: Dispatch>; + isSchema: boolean; + setIsSchema: React.Dispatch>; + showTextFromSchemaDialog: showTextFromSchemaDialogType; + setShowTextFromSchemaDialog: React.Dispatch>; + postProcessingTasks: string[]; + setPostProcessingTasks: React.Dispatch>; + queue: Queue; + setQueue: Dispatch>; + processedCount: number; + setProcessedCount: Dispatch>; + postProcessingVal: boolean; + setPostProcessingVal: Dispatch>; +} \ No newline at end of file diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index 08948ba87..b55c43817 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -75,6 +75,7 @@ export const chatModeLables = { entity_vector: 'entity search+vector', unavailableChatMode: 'Chat mode is unavailable when rows are selected', selected: 'Selected', + global_vector: 'global search+vector+fulltext' }; export const chatModes = process.env?.VITE_CHAT_MODES?.trim() != '' @@ -107,6 +108,10 @@ export const chatModes = mode: chatModeLables.entity_vector, description: 'Uses vector indexing on entity nodes for highly relevant entity-based search.', }, + { + mode : chatModeLables.global_vector, + description: 'Use vector and full-text indexing on community nodes to provide accurate, context-aware answers globally.' + } ]; export const chunkSize = process.env.VITE_CHUNK_SIZE ? parseInt(process.env.VITE_CHUNK_SIZE) : 1 * 1024 * 1024; @@ -234,8 +239,8 @@ export const POST_PROCESSING_JOBS: { title: string; description: string }[] = [ performing similarity-based searches.`, }, { - title: 'create_communities', - description: 'Create Communities identifies and groups similar entities, improving search accuracy and analysis.', + title: 'enable_communities', + description: 'Enable community creation across entities to use GraphRAG capabilities both local and global search.', }, ]; export const RETRY_OPIONS = [ diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index 97e7bda07..18fb69105 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -178,6 +178,7 @@ export const processGraphData = (neoNodes: ExtendedNode[], neoRels: ExtendedRela }; }); const finalNodes = newNodes.flat(); + // Process relationships const newRels: Relationship[] = neoRels.map((relations: any) => { return { id: relations.element_id, @@ -213,6 +214,7 @@ export const filterData = ( (type) => type !== 'Document' && type !== 'Chunk' && type !== '__Community__' ); // Only Document + Chunk + // const processedEntities = entityTypes.flatMap(item => item.includes(',') ? item.split(',') : item); if ( graphType.includes('DocumentChunk') && !graphType.includes('Entities') && @@ -245,6 +247,7 @@ export const filterData = ( nodeIds.has(rel.to) ); filteredScheme = Object.fromEntries(entityTypes.map((key) => [key, scheme[key]])) as Scheme; + console.log('labels', entityNodes); // Only Communities } else if ( graphType.includes('Communities') && @@ -336,6 +339,7 @@ export const filterData = ( filteredNodes = allNodes; filteredRelations = allRelationships; filteredScheme = scheme; + console.log('entity', filteredScheme); } return { filteredNodes, filteredRelations, filteredScheme }; }; @@ -428,6 +432,8 @@ export const getDescriptionForChatMode = (mode: string): string => { return 'Merges vector indexing, graph connections, and fulltext indexing for a comprehensive search approach, combining semantic similarity, contextual relevance, and keyword-based search for optimal results.'; case chatModeLables.entity_vector: return 'Combines entity node vector indexing with graph connections for accurate entity-based search, providing the most relevant response.'; + case chatModeLables.global_vector: + return 'Use vector and full-text indexing on community nodes to provide accurate, context-aware answers globally.' default: return 'Chat mode description not available'; // Fallback description } @@ -469,3 +475,10 @@ export function isAllowedHost(url: string, allowedHosts: string[]) { return false; } } + +export const getCheckboxConditions = (allNodes: ExtendedNode[]) => { + const isDocChunk = allNodes.some((n) => n.labels?.includes('Document')); + const isEntity = allNodes.some((n) => !n.labels?.includes('Document') || !n.labels?.includes('Chunk')); + const isgds = allNodes.some((n) => n.labels?.includes('__Community__')); + return { isDocChunk, isEntity, isgds }; +}; From 1180406a7a2f0eb7605a34ecfad37f2f584f9af9 Mon Sep 17 00:00:00 2001 From: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Date: Fri, 27 Sep 2024 10:01:48 +0000 Subject: [PATCH 136/292] Added elapsed time for extarction on each breakdown function --- backend/src/main.py | 86 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 68 insertions(+), 18 deletions(-) diff --git a/backend/src/main.py b/backend/src/main.py index 41942d500..ce8c9812a 100644 --- a/backend/src/main.py +++ b/backend/src/main.py @@ -292,14 +292,31 @@ def processing_source(uri, userName, password, database, model, file_name, pages Json response to API with fileName, nodeCount, relationshipCount, processingTime, status and model as attributes. """ + uri_latency = {} start_time = datetime.now() processing_source_start_time = time.time() + start_create_connection = time.time() graph = create_graph_database_connection(uri, userName, password, database) + end_create_connection = time.time() + elapsed_create_connection = end_create_connection - start_create_connection + logging.info(f'Time taken database connection: {elapsed_create_connection:.2f} seconds') + uri_latency["create_connection"] = f'{elapsed_create_connection:.2f}' graphDb_data_Access = graphDBdataAccess(graph) + start_get_chunkId_chunkDoc_list = time.time() total_chunks, chunkId_chunkDoc_list = get_chunkId_chunkDoc_list(graph, file_name, pages, retry_condition) + end_get_chunkId_chunkDoc_list = time.time() + elapsed_get_chunkId_chunkDoc_list = end_get_chunkId_chunkDoc_list - start_get_chunkId_chunkDoc_list + logging.info(f'Time taken to create list chunkids with chunk document: {elapsed_get_chunkId_chunkDoc_list:.2f} seconds') + uri_latency["create_list_chunk_and_document"] = f'{elapsed_get_chunkId_chunkDoc_list:.2f}' + + start_status_document_node = time.time() result = graphDb_data_Access.get_current_status_document_node(file_name) - + end_status_document_node = time.time() + elapsed_status_document_node = end_status_document_node - start_status_document_node + logging.info(f'Time taken to get the current status of document node: {elapsed_status_document_node:.2f} seconds') + uri_latency["get_status_document_node"] = f'{elapsed_status_document_node:.2f}' + select_chunks_with_retry=0 node_count = 0 rel_count = 0 @@ -319,8 +336,14 @@ def processing_source(uri, userName, password, database, model, file_name, pages obj_source_node.processed_chunk = 0+select_chunks_with_retry logging.info(file_name) logging.info(obj_source_node) - graphDb_data_Access.update_source_node(obj_source_node) + start_update_source_node = time.time() + graphDb_data_Access.update_source_node(obj_source_node) + end_update_source_node = time.time() + elapsed_update_source_node = end_update_source_node - start_update_source_node + logging.info(f'Time taken to update the document source node: {elapsed_update_source_node:.2f} seconds') + uri_latency["update_source_node"] = f'{elapsed_update_source_node:.2f}' + logging.info('Update the status as Processing') update_graph_chunk_processed = int(os.environ.get('UPDATE_GRAPH_CHUNKS_PROCESSED')) # selected_chunks = [] @@ -342,9 +365,12 @@ def processing_source(uri, userName, password, database, model, file_name, pages break else: processing_chunks_start_time = time.time() - node_count,rel_count = processing_chunks(selected_chunks,graph,uri, userName, password, database,file_name,model,allowedNodes,allowedRelationship,node_count, rel_count) - processing_chunks_end_time = time.time() - processing_chunks_start_time - logging.info(f"{update_graph_chunk_processed} chunks processed upto {select_chunks_upto} completed in {processing_chunks_end_time:.2f} seconds for file name {file_name}") + node_count,rel_count,latency_processed_chunk = processing_chunks(selected_chunks,graph,uri, userName, password, database,file_name,model,allowedNodes,allowedRelationship,node_count, rel_count) + processing_chunks_end_time = time.time() + processing_chunks_elapsed_end_time = processing_chunks_end_time - processing_chunks_start_time + logging.info(f"Time taken {update_graph_chunk_processed} chunks processed upto {select_chunks_upto} completed in {processing_chunks_elapsed_end_time:.2f} seconds for file name {file_name}") + uri_latency[f'processed_combine_chunk_{i}'] = f'{processing_chunks_elapsed_end_time:.2f}' + uri_latency[f'processed_chunk_detail_{i}'] = latency_processed_chunk end_time = datetime.now() processed_time = end_time - start_time @@ -390,16 +416,17 @@ def processing_source(uri, userName, password, database, model, file_name, pages else: delete_uploaded_local_file(merged_file_path, file_name) processing_source_func = time.time() - processing_source_start_time - logging.info(f"processing source function completed in {processing_source_func:.2f} seconds for file name {file_name}") - return { - "fileName": file_name, - "nodeCount": node_count, - "relationshipCount": rel_count, - "processingTime": round(processed_time.total_seconds(),2), - "status" : job_status, - "model" : model, - "success_count" : 1 - } + logging.info(f"Time taken to processing source function completed in {processing_source_func:.2f} seconds for file name {file_name}") + uri_latency["Processed_source"] = f'{processing_source_func:.2f}' + uri_latency["fileName"] = file_name + uri_latency["nodeCount"] = node_count + uri_latency["relationshipCount"] = rel_count + uri_latency["total_processing_time"] = round(processed_time.total_seconds(),2) + uri_latency["status"] = job_status + uri_latency["model"] = model + uri_latency["success_count"] = 1 + + return uri_latency else: logging.info('File does not process because it\'s already in Processing status') else: @@ -414,15 +441,38 @@ def processing_chunks(chunkId_chunkDoc_list,graph,uri, userName, password, datab graph = create_graph_database_connection(uri, userName, password, database) else: graph = create_graph_database_connection(uri, userName, password, database) - + + start_update_embedding = time.time() update_embedding_create_vector_index( graph, chunkId_chunkDoc_list, file_name) + end_update_embedding = time.time() + elapsed_update_embedding = end_update_embedding - start_update_embedding + logging.info(f'Time taken to update embedding in chunk node: {elapsed_update_embedding:.2f} seconds') + latency_processing_chunk = {"update_embedding" : f'{elapsed_update_embedding:.2f}'} logging.info("Get graph document list from models") + + start_entity_extraction = time.time() graph_documents = get_graph_from_llm(model, chunkId_chunkDoc_list, allowedNodes, allowedRelationship) + end_entity_extraction = time.time() + elapsed_entity_extraction = end_entity_extraction - start_entity_extraction + logging.info(f'Time taken to extract enitities from LLM Graph Builder: {elapsed_entity_extraction:.2f} seconds') + latency_processing_chunk["entity_extraction"] = f'{elapsed_entity_extraction:.2f}' cleaned_graph_documents = handle_backticks_nodes_relationship_id_type(graph_documents) + + start_save_graphDocuments = time.time() save_graphDocuments_in_neo4j(graph, cleaned_graph_documents) + end_save_graphDocuments = time.time() + elapsed_save_graphDocuments = end_save_graphDocuments - start_save_graphDocuments + logging.info(f'Time taken to save graph document in neo4j: {elapsed_save_graphDocuments:.2f} seconds') + latency_processing_chunk["save_graphDocuments"] = f'{elapsed_save_graphDocuments:.2f}' + chunks_and_graphDocuments_list = get_chunk_and_graphDocument(cleaned_graph_documents, chunkId_chunkDoc_list) + + start_relationship = time.time() merge_relationship_between_chunk_and_entites(graph, chunks_and_graphDocuments_list) - # return graph_documents + end_relationship = time.time() + elapsed_relationship = end_relationship - start_relationship + logging.info(f'Time taken to create relationship between chunk and entities: {elapsed_relationship:.2f} seconds') + latency_processing_chunk["relationship_between_chunk_entity"] = f'{elapsed_relationship:.2f}' distinct_nodes = set() relations = [] @@ -441,7 +491,7 @@ def processing_chunks(chunkId_chunkDoc_list,graph,uri, userName, password, datab rel_count += len(relations) print(f'node count internal func:{node_count}') print(f'relation count internal func:{rel_count}') - return node_count,rel_count + return node_count,rel_count,latency_processing_chunk def get_chunkId_chunkDoc_list(graph, file_name, pages, retry_condition): if retry_condition is None: From 9206fc89a773e862fe8d5b92f52c6c87e2a91968 Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Fri, 27 Sep 2024 11:15:24 +0000 Subject: [PATCH 137/292] lint and format fixes --- .../src/components/ChatBot/ChatInfoModal.tsx | 55 ++++++++----------- .../src/components/ChatBot/ChatModeToggle.tsx | 21 +++---- frontend/src/components/ChatBot/Chatbot.tsx | 32 ++++++----- frontend/src/components/Content.tsx | 33 +++++------ .../components/Graph/CheckboxSelection.tsx | 23 +++++--- .../src/components/Graph/GraphViewModal.tsx | 34 +++++++----- .../EntityExtractionSetting.tsx | 8 +++ frontend/src/context/UserMessages.tsx | 2 +- frontend/src/context/UsersFiles.tsx | 10 +++- frontend/src/services/ChunkEntitiesInfo.ts | 6 +- frontend/src/types.ts | 20 +++---- frontend/src/utils/Constants.ts | 9 +-- frontend/src/utils/Utils.ts | 2 +- 13 files changed, 139 insertions(+), 116 deletions(-) diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index 568868000..92ac3fd9a 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -43,18 +43,12 @@ const ChatInfoModal: React.FC = ({ cypher_query, graphonly_entities, error, - entities_ids + entities_ids, }) => { const { breakpoints } = tokens; const isTablet = useMediaQuery(`(min-width:${breakpoints.xs}) and (max-width: ${breakpoints.lg})`); const [activeTab, setActiveTab] = useState( - error?.length - ? 10 - : mode === chatModeLables.global_vector - ? 7 - : mode === chatModeLables.graph - ? 4 - : 3 + error?.length ? 10 : mode === chatModeLables.global_vector ? 7 : mode === chatModeLables.graph ? 4 : 3 ); const [infoEntities, setInfoEntities] = useState([]); const [communities, setCommunities] = useState([]); @@ -95,8 +89,12 @@ const ChatInfoModal: React.FC = ({ (async () => { setLoading(true); try { - const response = await chunkEntitiesAPI(userCredentials as UserCredentials, userCredentials?.database, nodeDetails, entities_ids, - mode, + const response = await chunkEntitiesAPI( + userCredentials as UserCredentials, + userCredentials?.database, + nodeDetails, + entities_ids, + mode ); if (response.data.status === 'Failure') { throw new Error(response.data.error); @@ -129,26 +127,25 @@ const ChatInfoModal: React.FC = ({ }) ); setRelationships(relationshipsData ?? []); - setCommunities(communitiesData.map((community: any) => { - const communityScore = nodeDetails?.communitydetails?.find((c: any) => - c.id === community.element_id); - return { - ...community, - score: communityScore?.score || 1 - }; - }) - .sort((a: any, b: any) => b.score - a.score) + setCommunities( + communitiesData + .map((community: any) => { + const communityScore = nodeDetails?.communitydetails?.find((c: any) => c.id === community.element_id); + return { + ...community, + score: communityScore?.score || 1, + }; + }) + .sort((a: any, b: any) => b.score - a.score) ); setChunks( chunksData .map((chunk: any) => { - const chunkScore = nodeDetails?.chunkdetails?.find((c: any) => - c.id - === chunk.id); + const chunkScore = nodeDetails?.chunkdetails?.find((c: any) => c.id === chunk.id); return { ...chunk, - score: chunkScore?.score + score: chunkScore?.score, }; }) .sort((a: any, b: any) => b.score - a.score) @@ -199,9 +196,9 @@ const ChatInfoModal: React.FC = ({ {mode != chatModeLables.graph ? Sources used : <>} {mode != chatModeLables.graph ? Chunks : <>} {mode === chatModeLables.graph_vector || - mode === chatModeLables.graph || - mode === chatModeLables.graph_vector_fulltext || - mode === chatModeLables.entity_vector ? ( + mode === chatModeLables.graph || + mode === chatModeLables.graph_vector_fulltext || + mode === chatModeLables.entity_vector ? ( Top Entities used ) : ( <> @@ -211,11 +208,7 @@ const ChatInfoModal: React.FC = ({ ) : ( <> )} - {mode === chatModeLables.entity_vector ? ( - Communities - ) : ( - <> - )} + {mode === chatModeLables.entity_vector ? Communities : <>} )} diff --git a/frontend/src/components/ChatBot/ChatModeToggle.tsx b/frontend/src/components/ChatBot/ChatModeToggle.tsx index b3d493236..df44985be 100644 --- a/frontend/src/components/ChatBot/ChatModeToggle.tsx +++ b/frontend/src/components/ChatBot/ChatModeToggle.tsx @@ -8,7 +8,7 @@ import { capitalizeWithPlus } from '../../utils/Utils'; import { useCredentials } from '../../context/UserCredentials'; export default function ChatModeToggle({ menuAnchor, - closeHandler = () => { }, + closeHandler = () => {}, open, anchorPortal = true, disableBackdrop = false, @@ -35,20 +35,17 @@ export default function ChatModeToggle({ return isGdsActive && isCommunityAllowed ? chatModes : chatModes?.filter( - (m) => - !m.mode.includes(chatModeLables.entity_vector) && - !m.mode.includes(chatModeLables.global_vector) - ); + (m) => !m.mode.includes(chatModeLables.entity_vector) && !m.mode.includes(chatModeLables.global_vector) + ); }, [isGdsActive, isCommunityAllowed]); const menuItems = useMemo(() => { return memoizedChatModes?.map((m) => { const isDisabled = Boolean( - selectedRows.length && - !(m.mode === chatModeLables.vector || m.mode === chatModeLables.graph_vector) + selectedRows.length && !(m.mode === chatModeLables.vector || m.mode === chatModeLables.graph_vector) ); const handleModeChange = () => { if (isDisabled) { - setchatMode(chatModeLables.graph_vector); + setchatMode(chatModeLables.graph_vector); } else { setchatMode(m.mode); } @@ -57,11 +54,11 @@ export default function ChatModeToggle({ return { title: (
    - + {m.mode.includes('+') ? capitalizeWithPlus(m.mode) : capitalize(m.mode)}
    - {m.description} + {m.description}
    ), @@ -71,12 +68,12 @@ export default function ChatModeToggle({ {chatMode === m.mode && ( <> - {chatModeLables.selected} + {chatModeLables.selected} )} {isDisabled && ( <> - {chatModeLables.unavailableChatMode} + {chatModeLables.unavailableChatMode} )} diff --git a/frontend/src/components/ChatBot/Chatbot.tsx b/frontend/src/components/ChatBot/Chatbot.tsx index 82e6dfed0..550d04c97 100644 --- a/frontend/src/components/ChatBot/Chatbot.tsx +++ b/frontend/src/components/ChatBot/Chatbot.tsx @@ -58,8 +58,8 @@ const Chatbot: FC = (props) => { }, }); - let selectedFileNames: CustomFile[] = filesData.filter(f => - selectedRows.includes(f.id) && ['Completed'].includes(f.status) + let selectedFileNames: CustomFile[] = filesData.filter( + (f) => selectedRows.includes(f.id) && ['Completed'].includes(f.status) ); const handleInputChange = (e: React.ChangeEvent) => { @@ -117,7 +117,7 @@ const Chatbot: FC = (props) => { graphonly_entities: response?.graphonly_entities, error: response.error, entitiysearchonly_entities: response.entitiysearchonly_entities, - nodeDetails: response?.nodeDetails + nodeDetails: response?.nodeDetails, }, ]); } else { @@ -217,7 +217,7 @@ const Chatbot: FC = (props) => { error, entitiysearchonly_entities, chatEntities, - nodeDetails: chatnodedetails + nodeDetails: chatnodedetails, }; simulateTypingEffect(finalbotReply); } catch (error) { @@ -322,8 +322,9 @@ const Chatbot: FC = (props) => { @@ -335,10 +336,11 @@ const Chatbot: FC = (props) => { } >
    {chat.message}
    @@ -369,7 +371,7 @@ const Chatbot: FC = (props) => { setgraphEntitites(chat.graphonly_entities ?? []); setEntitiesModal(chat.entities ?? []); setmessageError(chat.error ?? ''); - setNodeDetailsModal(chat.nodeDetails ?? {}) + setNodeDetailsModal(chat.nodeDetails ?? {}); }} > {' '} @@ -423,8 +425,9 @@ const Chatbot: FC = (props) => {
    = (props) => { disabled={loading || !connectionStatus} size='medium' > - {buttonCaptions.ask} {selectedFileNames != undefined && selectedFileNames.length > 0 && `(${selectedFileNames.length})`} + {buttonCaptions.ask}{' '} + {selectedFileNames != undefined && selectedFileNames.length > 0 && `(${selectedFileNames.length})`}
    diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 3f7564461..d6f9c709d 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -95,7 +95,6 @@ const Content: React.FC = ({ queue, processedCount, setProcessedCount, - setPostProcessingVal } = useFileContext(); const [viewPoint, setViewPoint] = useState<'tableView' | 'showGraphView' | 'chatInfoView'>('tableView'); const [showDeletePopUp, setshowDeletePopUp] = useState(false); @@ -162,7 +161,7 @@ const Content: React.FC = ({ (async () => { showNormalToast('Some Q&A functionality will only be available afterwards.'); await postProcessing(userCredentials as UserCredentials, postProcessingTasks); - showSuccessToast('All Q&A functionality is available now.'); + showSuccessToast('All Q&A functionality is available now.'); })(); } }, [processedCount, userCredentials, queue]); @@ -512,8 +511,9 @@ const Content: React.FC = ({ const handleOpenGraphClick = () => { const bloomUrl = process.env.VITE_BLOOM_URL; const uriCoded = userCredentials?.uri.replace(/:\d+$/, ''); - const connectURL = `${uriCoded?.split('//')[0]}//${userCredentials?.userName}@${uriCoded?.split('//')[1]}:${userCredentials?.port ?? '7687' - }`; + const connectURL = `${uriCoded?.split('//')[0]}//${userCredentials?.userName}@${uriCoded?.split('//')[1]}:${ + userCredentials?.port ?? '7687' + }`; const encodedURL = encodeURIComponent(connectURL); const replacedUrl = bloomUrl?.replace('{CONNECT_URL}', encodedURL); window.open(replacedUrl, '_blank'); @@ -523,10 +523,10 @@ const Content: React.FC = ({ isLeftExpanded && isRightExpanded ? 'contentWithExpansion' : isRightExpanded - ? 'contentWithChatBot' - : !isLeftExpanded && !isRightExpanded - ? 'w-[calc(100%-128px)]' - : 'contentWithDropzoneExpansion'; + ? 'contentWithChatBot' + : !isLeftExpanded && !isRightExpanded + ? 'w-[calc(100%-128px)]' + : 'contentWithDropzoneExpansion'; const handleGraphView = () => { setOpenGraphView(true); @@ -557,12 +557,12 @@ const Content: React.FC = ({ return prev.map((f) => { return f.name === filename ? { - ...f, - status: 'Reprocess', - processingProgress: isStartFromBegining ? 0 : f.processingProgress, - NodesCount: isStartFromBegining ? 0 : f.NodesCount, - relationshipCount: isStartFromBegining ? 0 : f.relationshipCount, - } + ...f, + status: 'Reprocess', + processingProgress: isStartFromBegining ? 0 : f.processingProgress, + NodesCount: isStartFromBegining ? 0 : f.NodesCount, + relationshipCount: isStartFromBegining ? 0 : f.relationshipCount, + } : f; }); }); @@ -851,8 +851,9 @@ const Content: React.FC = ({ handleGenerateGraph={processWaitingFilesOnRefresh} > diff --git a/frontend/src/components/Graph/CheckboxSelection.tsx b/frontend/src/components/Graph/CheckboxSelection.tsx index 738a1dd01..d0a3429f2 100644 --- a/frontend/src/components/Graph/CheckboxSelection.tsx +++ b/frontend/src/components/Graph/CheckboxSelection.tsx @@ -3,15 +3,24 @@ import React from 'react'; import { CheckboxSectionProps } from '../../types'; import { graphLabels } from '../../utils/Constants'; -const CheckboxSelection: React.FC = ({ graphType, loading, handleChange, isgds, isDocChunk, isEntity }) => ( +const CheckboxSelection: React.FC = ({ + graphType, + loading, + handleChange, + isgds, + isDocChunk, + isEntity, +}) => (
    - {isDocChunk && ( handleChange('DocumentChunk')} - />)} + {isDocChunk && ( + handleChange('DocumentChunk')} + /> + )} {isEntity && ( = ({ graphType.includes('DocumentChunk') && graphType.includes('Entities') ? queryMap.DocChunkEntities : graphType.includes('DocumentChunk') - ? queryMap.DocChunks - : graphType.includes('Entities') - ? queryMap.Entities - : ''; + ? queryMap.DocChunks + : graphType.includes('Entities') + ? queryMap.Entities + : ''; // fit graph to original position const handleZoomToFit = () => { @@ -136,10 +136,10 @@ const GraphViewModal: React.FunctionComponent = ({ const nodeRelationshipData = viewPoint === graphLabels.showGraphView ? await graphQueryAPI( - userCredentials as UserCredentials, - graphQuery, - selectedRows?.map((f) => f.name) - ) + userCredentials as UserCredentials, + graphQuery, + selectedRows?.map((f) => f.name) + ) : await graphQueryAPI(userCredentials as UserCredentials, graphQuery, [inspectedName ?? '']); return nodeRelationshipData; } catch (error: any) { @@ -152,9 +152,13 @@ const GraphViewModal: React.FunctionComponent = ({ try { const result = await fetchData(); if (result && result.data.data.nodes.length > 0) { - const neoNodes = result.data.data.nodes.map((f: Node) => f).filter((node: ExtendedNode) => node.labels.length === 1); - const nodeIds = new Set(neoNodes.map((node:any) => node.element_id)); - const neoRels = result.data.data.relationships.map((f: Relationship) => f).filter((rel: any) => nodeIds.has(rel.end_node_element_id) && nodeIds.has(rel.start_node_element_id)); + const neoNodes = result.data.data.nodes + .map((f: Node) => f) + .filter((node: ExtendedNode) => node.labels.length === 1); + const nodeIds = new Set(neoNodes.map((node: any) => node.element_id)); + const neoRels = result.data.data.relationships + .map((f: Relationship) => f) + .filter((rel: any) => nodeIds.has(rel.end_node_element_id) && nodeIds.has(rel.start_node_element_id)); const { finalNodes, finalRels, schemeVal } = processGraphData(neoNodes, neoRels); if (mode === 'refreshMode') { @@ -248,8 +252,8 @@ const GraphViewModal: React.FunctionComponent = ({ match && viewPoint === graphLabels.showGraphView ? 100 : match && viewPoint !== graphLabels.showGraphView - ? 50 - : graphLabels.nodeSize, + ? 50 + : graphLabels.nodeSize, }; }); // deactivating any active relationships @@ -358,8 +362,8 @@ const GraphViewModal: React.FunctionComponent = ({ isActive && viewPoint === graphLabels.showGraphView ? 100 : isActive && viewPoint !== graphLabels.showGraphView - ? 50 - : graphLabels.nodeSize, + ? 50 + : graphLabels.nodeSize, }; }); // deactivating any active relationships diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/EnitityExtraction/EntityExtractionSetting.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/EnitityExtraction/EntityExtractionSetting.tsx index 5bbd4607a..8a7362d26 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/EnitityExtraction/EntityExtractionSetting.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/EnitityExtraction/EntityExtractionSetting.tsx @@ -217,6 +217,14 @@ export default function EntityExtractionSetting({ setSelectedRels(relationshipTypeOptions); setIsSchema(true); localStorage.setItem('isSchema', JSON.stringify(true)); + localStorage.setItem( + 'selectedNodeLabels', + JSON.stringify({ db: userCredentials?.uri, selectedOptions: nodeLabelOptions }) + ); + localStorage.setItem( + 'selectedRelationshipLabels', + JSON.stringify({ db: userCredentials?.uri, selectedOptions: relationshipTypeOptions }) + ); }, [nodeLabelOptions, relationshipTypeOptions]); const handleClear = () => { diff --git a/frontend/src/context/UserMessages.tsx b/frontend/src/context/UserMessages.tsx index 1bbed905d..0e7b7abde 100644 --- a/frontend/src/context/UserMessages.tsx +++ b/frontend/src/context/UserMessages.tsx @@ -15,7 +15,7 @@ const MessageContextWrapper: FC = ({ children }) = messages, setMessages, clearHistoryData, - setClearHistoryData + setClearHistoryData, }; return {children}; }; diff --git a/frontend/src/context/UsersFiles.tsx b/frontend/src/context/UsersFiles.tsx index 7ff7e28c4..04a435f07 100644 --- a/frontend/src/context/UsersFiles.tsx +++ b/frontend/src/context/UsersFiles.tsx @@ -1,5 +1,11 @@ import { createContext, useContext, useState, FC, useEffect } from 'react'; -import { CustomFile, FileContextProviderProps, FileContextType, OptionType, showTextFromSchemaDialogType } from '../types'; +import { + CustomFile, + FileContextProviderProps, + FileContextType, + OptionType, + showTextFromSchemaDialogType, +} from '../types'; import { chatModeLables, defaultLLM } from '../utils/Constants'; import { useCredentials } from './UserCredentials'; import Queue from '../utils/Queue'; @@ -85,7 +91,7 @@ const FileContextProvider: FC = ({ children }) => { processedCount, setProcessedCount, postProcessingVal, - setPostProcessingVal + setPostProcessingVal, }; return {children}; }; diff --git a/frontend/src/services/ChunkEntitiesInfo.ts b/frontend/src/services/ChunkEntitiesInfo.ts index 39d9f8c2e..dbbbcbb5b 100644 --- a/frontend/src/services/ChunkEntitiesInfo.ts +++ b/frontend/src/services/ChunkEntitiesInfo.ts @@ -4,9 +4,9 @@ import api from '../API/Index'; const chunkEntitiesAPI = async ( userCredentials: UserCredentials, database: string = 'neo4j', - nodeDetails: (nodeDetailsProps), - entities:(string)[], - mode: string, + nodeDetails: nodeDetailsProps, + entities: string[], + mode: string ) => { try { const formData = new FormData(); diff --git a/frontend/src/types.ts b/frontend/src/types.ts index b280cc5d6..f407ca350 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -236,7 +236,7 @@ export type ChatbotProps = { isFullScreen?: boolean; connectionStatus: boolean; }; -export interface WikipediaModalTypes extends Omit { } +export interface WikipediaModalTypes extends Omit {} export interface GraphViewModalProps { open: boolean; @@ -646,7 +646,7 @@ export interface MessageContextType { messages: Messages[] | []; setMessages: Dispatch>; clearHistoryData: boolean; - setClearHistoryData: Dispatch> + setClearHistoryData: Dispatch>; } export interface DatabaseStatusProps { @@ -682,7 +682,7 @@ export type CommunitiesProps = { export interface entity { id: string; score: number; -}; +} export interface community { id: string; @@ -690,15 +690,15 @@ export interface community { } export interface nodeDetailsProps { - chunkdetails?: ChunkDetail[], - entitydetails?: entity[], - communitydetails?: community[] + chunkdetails?: ChunkDetail[]; + entitydetails?: entity[]; + communitydetails?: community[]; } export type entityProps = { - entityids: [], - relationshipids: [] -} + entityids: []; + relationshipids: []; +}; export interface showTextFromSchemaDialogType { triggeredFrom: string; @@ -737,4 +737,4 @@ export interface FileContextType { setProcessedCount: Dispatch>; postProcessingVal: boolean; setPostProcessingVal: Dispatch>; -} \ No newline at end of file +} diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index b55c43817..8a0fa5ff3 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -75,7 +75,7 @@ export const chatModeLables = { entity_vector: 'entity search+vector', unavailableChatMode: 'Chat mode is unavailable when rows are selected', selected: 'Selected', - global_vector: 'global search+vector+fulltext' + global_vector: 'global search+vector+fulltext', }; export const chatModes = process.env?.VITE_CHAT_MODES?.trim() != '' @@ -109,9 +109,10 @@ export const chatModes = description: 'Uses vector indexing on entity nodes for highly relevant entity-based search.', }, { - mode : chatModeLables.global_vector, - description: 'Use vector and full-text indexing on community nodes to provide accurate, context-aware answers globally.' - } + mode: chatModeLables.global_vector, + description: + 'Use vector and full-text indexing on community nodes to provide accurate, context-aware answers globally.', + }, ]; export const chunkSize = process.env.VITE_CHUNK_SIZE ? parseInt(process.env.VITE_CHUNK_SIZE) : 1 * 1024 * 1024; diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index 18fb69105..1970ee754 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -433,7 +433,7 @@ export const getDescriptionForChatMode = (mode: string): string => { case chatModeLables.entity_vector: return 'Combines entity node vector indexing with graph connections for accurate entity-based search, providing the most relevant response.'; case chatModeLables.global_vector: - return 'Use vector and full-text indexing on community nodes to provide accurate, context-aware answers globally.' + return 'Use vector and full-text indexing on community nodes to provide accurate, context-aware answers globally.'; default: return 'Chat mode description not available'; // Fallback description } From 04058166a07bbf057e0f774c9b9222ce928a9749 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Fri, 27 Sep 2024 11:28:00 +0000 Subject: [PATCH 138/292] removed dev logs --- frontend/src/components/ChatBot/Communities.tsx | 1 - frontend/src/components/Content.tsx | 7 +++---- .../Popups/ConnectionModal/ConnectionModal.tsx | 1 - .../components/Popups/GraphEnhancementDialog/index.tsx | 3 +-- frontend/src/utils/Constants.ts | 10 ++-------- frontend/src/utils/Utils.ts | 2 -- 6 files changed, 6 insertions(+), 18 deletions(-) diff --git a/frontend/src/components/ChatBot/Communities.tsx b/frontend/src/components/ChatBot/Communities.tsx index 11869d3d4..e2092c101 100644 --- a/frontend/src/components/ChatBot/Communities.tsx +++ b/frontend/src/components/ChatBot/Communities.tsx @@ -4,7 +4,6 @@ import ReactMarkdown from 'react-markdown'; import { CommunitiesProps } from '../../types'; const CommunitiesInfo: FC = ({ loading, communities }) => { - console.log('communities', communities); return ( <> {loading ? ( diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index d6f9c709d..9c32294fd 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -185,7 +185,6 @@ const Content: React.FC = ({ if (connection != null) { (async () => { const parsedData = JSON.parse(connection); - console.log(parsedData.uri); const response = await connectAPI( parsedData.uri, parsedData.user, @@ -473,12 +472,12 @@ const Content: React.FC = ({ } data = triggerBatchProcessing(filesTobeSchedule, filesTobeProcessed, true, true); } - Promise.allSettled(data).then(async (_) => { + Promise.allSettled(data).then((_) => { setextractLoading(false); }); } else if (queueFiles && !queue.isEmpty() && processingFilesCount < batchSize) { data = scheduleBatchWiseProcess(queue.items, true); - Promise.allSettled(data).then(async (_) => { + Promise.allSettled(data).then((_) => { setextractLoading(false); }); } else { @@ -497,7 +496,7 @@ const Content: React.FC = ({ } else { data = triggerBatchProcessing(queue.items, queue.items as CustomFile[], true, false); } - Promise.allSettled(data).then(async (_) => { + Promise.allSettled(data).then((_) => { setextractLoading(false); }); } else { diff --git a/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx b/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx index 618cc7b80..ad7e7b48e 100644 --- a/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx +++ b/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx @@ -210,7 +210,6 @@ export default function ConnectionModal({ const isgdsActive = response.data.data.gds_status; const isReadOnlyUser = !response.data.data.write_access; setGdsActive(isgdsActive); - console.log({ isReadOnlyUser }); setIsReadOnlyUser(isReadOnlyUser); localStorage.setItem( 'neo4j.connection', diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/index.tsx index 9e409d8e2..c4d9ee2f7 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/index.tsx @@ -29,9 +29,8 @@ export default function GraphEnhancementDialog({ const orphanNodesDeleteHandler = async (selectedEntities: string[]) => { try { setorphanDeleteAPIloading(true); - const response = await deleteOrphanAPI(userCredentials as UserCredentials, selectedEntities); + await deleteOrphanAPI(userCredentials as UserCredentials, selectedEntities); setorphanDeleteAPIloading(false); - console.log(response); } catch (error) { setorphanDeleteAPIloading(false); console.log(error); diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index 8a0fa5ff3..daf3ef0f2 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -43,7 +43,6 @@ export const llms = 'openai-gpt-3.5', 'openai-gpt-4o', 'openai-gpt-4o-mini', - 'gemini-1.0-pro', 'gemini-1.5-pro', 'gemini-1.5-flash', 'azure_ai_gpt_35', @@ -57,15 +56,10 @@ export const llms = export const defaultLLM = llms?.includes('openai-gpt-4o') ? 'openai-gpt-4o' - : llms?.includes('gemini-1.0-pro') - ? 'gemini-1.0-pro' + : llms?.includes('gemini-1.5-pro') + ? 'gemini-1.5-pro' : 'diffbot'; -// export const chatModes = -// process.env?.VITE_CHAT_MODES?.trim() != '' -// ? process.env.VITE_CHAT_MODES?.split(',') -// : ['vector', 'graph', 'graph+vector', 'fulltext', 'graph+vector+fulltext', 'local community', 'global community']; - export const chatModeLables = { vector: 'vector', graph: 'graph', diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index 1970ee754..1d8f3be07 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -247,7 +247,6 @@ export const filterData = ( nodeIds.has(rel.to) ); filteredScheme = Object.fromEntries(entityTypes.map((key) => [key, scheme[key]])) as Scheme; - console.log('labels', entityNodes); // Only Communities } else if ( graphType.includes('Communities') && @@ -339,7 +338,6 @@ export const filterData = ( filteredNodes = allNodes; filteredRelations = allRelationships; filteredScheme = scheme; - console.log('entity', filteredScheme); } return { filteredNodes, filteredRelations, filteredScheme }; }; From c9844b70c1590f32927ebbf5ffa08cd6c3462a3a Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Fri, 27 Sep 2024 12:08:37 +0000 Subject: [PATCH 139/292] communities fix --- .../src/components/ChatBot/ChatInfoModal.tsx | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index 92ac3fd9a..84cb2ce88 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -128,12 +128,14 @@ const ChatInfoModal: React.FC = ({ ); setRelationships(relationshipsData ?? []); setCommunities( - communitiesData - .map((community: any) => { - const communityScore = nodeDetails?.communitydetails?.find((c: any) => c.id === community.element_id); + (communitiesData || []) + .map((community: { element_id: string }) => { + const communityScore = nodeDetails?.communitydetails?.find((c: { id: string }) => + c.id + === community.element_id); return { ...community, - score: communityScore?.score || 1, + score: communityScore?.score ?? 1, }; }) .sort((a: any, b: any) => b.score - a.score) @@ -196,9 +198,9 @@ const ChatInfoModal: React.FC = ({ {mode != chatModeLables.graph ? Sources used : <>} {mode != chatModeLables.graph ? Chunks : <>} {mode === chatModeLables.graph_vector || - mode === chatModeLables.graph || - mode === chatModeLables.graph_vector_fulltext || - mode === chatModeLables.entity_vector ? ( + mode === chatModeLables.graph || + mode === chatModeLables.graph_vector_fulltext || + mode === chatModeLables.entity_vector ? ( Top Entities used ) : ( <> From 085a0e40b82bacac337a746c233ebbc4a8189c21 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Fri, 27 Sep 2024 12:44:01 +0000 Subject: [PATCH 140/292] disabled the generate graph for read only user --- frontend/src/components/Content.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 9c32294fd..5aa6ce98e 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -870,7 +870,7 @@ const Content: React.FC = ({ placement='top' label='generate graph' onClick={onClickHandler} - disabled={disableCheck} + disabled={disableCheck || isReadOnlyUser} className='mr-0.5' size={isTablet ? 'small' : 'medium'} > From 78137505f51baa8de37a349379db1b1a547b9dc2 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Fri, 27 Sep 2024 12:47:11 +0000 Subject: [PATCH 141/292] format fixes --- frontend/src/components/ChatBot/ChatInfoModal.tsx | 12 ++++++------ frontend/src/components/FileTable.tsx | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index 84cb2ce88..0d56978f7 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -130,9 +130,9 @@ const ChatInfoModal: React.FC = ({ setCommunities( (communitiesData || []) .map((community: { element_id: string }) => { - const communityScore = nodeDetails?.communitydetails?.find((c: { id: string }) => - c.id - === community.element_id); + const communityScore = nodeDetails?.communitydetails?.find( + (c: { id: string }) => c.id === community.element_id + ); return { ...community, score: communityScore?.score ?? 1, @@ -198,9 +198,9 @@ const ChatInfoModal: React.FC = ({ {mode != chatModeLables.graph ? Sources used : <>} {mode != chatModeLables.graph ? Chunks : <>} {mode === chatModeLables.graph_vector || - mode === chatModeLables.graph || - mode === chatModeLables.graph_vector_fulltext || - mode === chatModeLables.entity_vector ? ( + mode === chatModeLables.graph || + mode === chatModeLables.graph_vector_fulltext || + mode === chatModeLables.entity_vector ? ( Top Entities used ) : ( <> diff --git a/frontend/src/components/FileTable.tsx b/frontend/src/components/FileTable.tsx index 2d0d690aa..01ab3a0aa 100644 --- a/frontend/src/components/FileTable.tsx +++ b/frontend/src/components/FileTable.tsx @@ -52,7 +52,7 @@ const FileTable = forwardRef((props, ref) => { const { isExpanded, connectionStatus, setConnectionStatus, onInspect, onRetry } = props; const { filesData, setFilesData, model, rowSelection, setRowSelection, setSelectedRows, setProcessedCount, queue } = useFileContext(); - const { userCredentials } = useCredentials(); + const { userCredentials, isReadOnlyUser } = useCredentials(); const columnHelper = createColumnHelper(); const [columnFilters, setColumnFilters] = useState([]); const [isLoading, setIsLoading] = useState(false); @@ -148,7 +148,7 @@ const FileTable = forwardRef((props, ref) => { {info.getValue()} {(info.getValue() === 'Completed' || info.getValue() === 'Failed' || - info.getValue() === 'Cancelled') && ( + (info.getValue() === 'Cancelled' && !isReadOnlyUser)) && ( Date: Fri, 27 Sep 2024 12:54:10 +0000 Subject: [PATCH 142/292] graph labels change --- frontend/src/components/ChatBot/ChatInfoModal.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index 84cb2ce88..cde0bbdea 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -32,6 +32,7 @@ import EntitiesInfo from './EntitiesInfo'; import SourcesInfo from './SourcesInfo'; import CommunitiesInfo from './Communities'; import { chatModeLables } from '../../utils/Constants'; +import { Relationship } from '@neo4j-nvl/base'; const ChatInfoModal: React.FC = ({ sources, @@ -99,8 +100,11 @@ const ChatInfoModal: React.FC = ({ if (response.data.status === 'Failure') { throw new Error(response.data.error); } - const nodesData = response?.data?.data?.nodes; - const relationshipsData = response?.data?.data?.relationships; + const nodesData = response?.data?.data?.nodes.map((f: Node) => f) + .filter((node: ExtendedNode) => node.labels.length === 1); + const nodeIds = new Set(nodesData.map((node: any) => node.element_id)); + const relationshipsData = response?.data?.data?.relationships.map((f: Relationship) => f) + .filter((rel: any) => nodeIds.has(rel.end_node_element_id) && nodeIds.has(rel.start_node_element_id));; const communitiesData = response?.data?.data?.community_data; const chunksData = response?.data?.data?.chunk_data; From e0e97fbfe213e5079a71633d9c2ea29439de4acf Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Fri, 27 Sep 2024 13:03:35 +0000 Subject: [PATCH 143/292] added the readonly check for already added waiting files --- frontend/src/components/Content.tsx | 4 ++-- frontend/src/components/FileTable.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 5aa6ce98e..53bf47058 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -154,7 +154,7 @@ const Content: React.FC = ({ if (afterFirstRender) { localStorage.setItem('processedCount', JSON.stringify({ db: userCredentials?.uri, count: processedCount })); } - if (processedCount == batchSize) { + if (processedCount == batchSize && !isReadOnlyUser) { handleGenerateGraph([], true); } if (processedCount === 1 && queue.isEmpty()) { @@ -164,7 +164,7 @@ const Content: React.FC = ({ showSuccessToast('All Q&A functionality is available now.'); })(); } - }, [processedCount, userCredentials, queue]); + }, [processedCount, userCredentials, queue, isReadOnlyUser]); useEffect(() => { if (afterFirstRender) { diff --git a/frontend/src/components/FileTable.tsx b/frontend/src/components/FileTable.tsx index 01ab3a0aa..8855a746e 100644 --- a/frontend/src/components/FileTable.tsx +++ b/frontend/src/components/FileTable.tsx @@ -701,7 +701,7 @@ const FileTable = forwardRef((props, ref) => { }, [connectionStatus, userCredentials]); useEffect(() => { - if (connectionStatus && filesData.length && onlyfortheFirstRender) { + if (connectionStatus && filesData.length && onlyfortheFirstRender && !isReadOnlyUser) { const processingFilesCount = filesData.filter((f) => f.status === 'Processing').length; if (processingFilesCount) { if (processingFilesCount === 1) { @@ -718,7 +718,7 @@ const FileTable = forwardRef((props, ref) => { } onlyfortheFirstRender = false; } - }, [connectionStatus, filesData.length]); + }, [connectionStatus, filesData.length, isReadOnlyUser]); const cancelHandler = async (fileName: string, id: string, fileSource: string) => { setFilesData((prevfiles) => From 42f4c82b6ae55cddfccf73633e3aa421a5e10939 Mon Sep 17 00:00:00 2001 From: kaustubh-darekar Date: Fri, 27 Sep 2024 13:20:45 +0000 Subject: [PATCH 144/292] Retriever evaluation using RAGAS --- experiments/RAGAS_evaluation.csv | 103 + experiments/modes_comparison_RAGAS.ipynb | 3442 ++++++++++++++++++++++ 2 files changed, 3545 insertions(+) create mode 100644 experiments/RAGAS_evaluation.csv create mode 100644 experiments/modes_comparison_RAGAS.ipynb diff --git a/experiments/RAGAS_evaluation.csv b/experiments/RAGAS_evaluation.csv new file mode 100644 index 000000000..3e1347135 --- /dev/null +++ b/experiments/RAGAS_evaluation.csv @@ -0,0 +1,103 @@ +question,mode,answer,contexts,ground_truth,question_complexity,context_precision,context_recall,faithfulness,answer_relevancy,answer_correctness +What issues did Amazon's Elastic Block Storage (EBS) service face in 2012 and how did it affect the company?,vector,"Amazon's Elastic Block Storage (EBS) service faced downtime in 2012 due to an electric outage at Amazon's U.S. East data center in Virginia. The outage was significant as it impacted the availability of services, causing inconvenience and discomfort to customers who regularly used the website. This highlighted the critical need for major upgrades to the U.S. East data center to prevent future service disruptions and maintain customer satisfaction.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\nDocument end\n']","In 2012, Amazon's Elastic Block Storage (EBS) service faced several downtimes due to electric outages. The main problem originated from Amazon's U.S. East data center in Virginia, which is the biggest and oldest data center and has been causing outage issues. These server crashes brought inconvenience and discomfort to the customers who use the website regularly. The company needed to do major upgrades on the U.S. East data center to prevent the services from going down in the future.",simple,0.9999999999,1.0,0.75,0.924069484158001,0.7698959011659919 +What issues did Amazon's Elastic Block Storage (EBS) service face in 2012 and how did it affect the company?,fulltext,"Amazon's Elastic Block Storage (EBS) service faced downtime in 2012 due to an electric outage at Amazon's U.S. East data center in Virginia. The outage was significant as it impacted the availability of services, causing inconvenience and discomfort to customers who regularly used the website. This highlighted the critical need for major upgrades to the U.S. East data center to prevent future service disruptions and maintain customer satisfaction.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \nDocument end\n\n\nDocument start\nThis Document belongs to the source github-recovery-codes.txt\nContent: e6b17-50e48\n----\ne5ab9-b2238\nDocument end\n\n\nDocument start\nThis Document belongs to the source https://en.wikipedia.org/wiki/Lord_Kelvin\nContent: ations would approach the deformation for the pure elastic material σ 0 / E {\\displaystyle \\sigma _{0}/E} with the difference decaying exponentially: ε \nDocument end\n']","In 2012, Amazon's Elastic Block Storage (EBS) service faced several downtimes due to electric outages. The main problem originated from Amazon's U.S. East data center in Virginia, which is the biggest and oldest data center and has been causing outage issues. These server crashes brought inconvenience and discomfort to the customers who use the website regularly. The company needed to do major upgrades on the U.S. East data center to prevent the services from going down in the future.",simple,0.9999999999,1.0,0.625,0.9240259114880655,0.797545745335543 +What issues did Amazon's Elastic Block Storage (EBS) service face in 2012 and how did it affect the company?,entity search+vector,"In 2012, Amazon's Elastic Block Storage (EBS) service faced a significant outage that impacted various online services and websites relying on Amazon Web Services (AWS). This outage led to widespread disruptions for companies using AWS, including popular websites like Reddit, Pinterest, and Netflix. The downtime caused by the EBS service issue resulted in financial losses for businesses, tarnished Amazon's reputation for reliability, and raised concerns about the dependency on cloud services for critical operations. The incident highlighted the importance of implementing robust backup and disaster recovery strategies when utilizing cloud services like EBS to mitigate such risks in the future.","[""Document start\nThis Document belongs to the source unknown\nContent: chunks:\n- \t\r \xa0 3 online payment methods such as online banking and PayPal create more convenience in purchase transactions, which in turn enhances customers’ online shopping experience. Also, the invention of electronic devices such as smartphones deliver easy and convenient transaction processes, further facilitating online shopping. For instance, Amazon recently released a smartphone app for their Kindle services, allowing users to conveniently access the online sales platform and review products before purchasing. In the future, the use of 3D virtual technology to market products will also take online shopping to new heights. Political/Legal In the modern day environment, firms must be cautious when they deal with international policies on online distribution. In the U.S., electronic commerce firms are regulated by the Federal Trade Commission, which regulates online advertising and the security of consumers’ personal information. On the other hand, International Consumer Protection and Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions \n- Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers. Demographic As the world’s population is aging rapidly, baby boomers are moving towards retirement so that they will have weaker purchasing power. Thus, generation X and Y have become companies’ target markets for product selling. These generations are technologically adept and tend to engage more in online purchasing. Based on a survey, 62 percent of Generation Y liked to purchase things online, as compared to 32 percent of those aged older than 50. Organizations \n- \t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\ncommunities:\n- Alphabet is a major organization that serves as the parent company to several subsidiaries, including Verily, Waymo, Google Cloud, and YouTube. Ruth Porat holds the position of Chief Financial Officer (CFO) at Alphabet. Additionally, DeepMind is reported as part of Alphabet and also functions as a subsidiary. This network of companies highlights Alphabet's diverse interests in technology, healthcare, and media.\n- Amazon is a rapidly growing multinational e-commerce retailer based in America with a significant international presence. It faces competition from major organizations such as eBay, Barnes and Noble, and Wal-Mart. eBay and Barnes and Noble are noted for their product breadth and geographic market coverage, while Wal-Mart is recognized as the world's largest retail chain, employing a cost leadership strategy.\n\nAmazon competes with eBay, which utilizes both cost leadership and differentiation strategies. Barnes and Noble also competes with Amazon, employing an integrated focused cost leadership/differentiation strategy. Wal-Mart, another competitor, uses a cost leadership approach.\n\nAmazon is actively investing in various technologies and products, including video content, cloud services, and its Kindle product. It utilizes technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations. The company has also released a smartphone app and is located at the U.S. East Data Center.\n\nAmazon sees opportunities in emerging markets like China, which has a large population and growing disposable income. It is focused on capturing the global market and has invested in distribution centers to support this goal. The company discloses information about online sales taxes and is regulated by the Federal Trade Commission. Additionally, it receives support from the International Consumer Protection and Enforcement Network.\n- Amazon is a rapidly growing multinational e-commerce retailer based in America with a significant international presence. It faces competition from major organizations such as eBay, Barnes and Noble, and Wal-Mart. eBay and Barnes and Noble are noted for their product breadth and geographic market coverage, while Wal-Mart is recognized as the world's largest retail chain, employing a cost leadership strategy.\n\nAmazon competes with eBay, which utilizes both cost leadership and differentiation strategies. Barnes and Noble also competes with Amazon, employing an integrated focused cost leadership/differentiation strategy. Wal-Mart, another competitor, uses a cost leadership approach.\n\nAmazon is actively investing in various technologies and products, including video content, cloud services, and its Kindle product. It utilizes technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations. The company has also released a smartphone app and is located at the U.S. East Data Center.\n\nAmazon sees opportunities in emerging markets like China, which has a large population and growing disposable income. It is focused on capturing the global market and has invested in distribution centers to support this goal. The company discloses information about online sales taxes and is regulated by the Federal Trade Commission. Additionally, it receives support from the International Consumer Protection and Enforcement Network.\nrelationships:\n- Amazon USES Elastic Block Storage (Ebs)\n- Amazon LOCATED_AT U.S. East Data Center\nentities:\n- Technology:Elastic Block Storage (Ebs) \n- Electronic_Commerce_Firms \n- Organization:Amazon Fastest-growing, multinational e-commerce retailer in America with international presence.\n- Storage:Persistent Storage \n- Concept:E-Commerce \n- Organization:Icpen Finds ways to tackle consumer problems involving cross-border transactions.\n- Location:U.S. East Data Center \n- Organization:Morgan Grenfell Asset Management \n- Organization:Google Cloud \n- Concept:Threat_Of_New_Entrants Considered low due to low capital investment costs but high infrastructure and inventory requirements.\noutside:\n nodes:\n - Organization:Ebay Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.\n - Organization:Barnes And Noble Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.\n - Organization:Wal-Mart World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.\n - Activity:Online Shopping \n - Country:India Emerging country with large population and growing disposable income.\n - Organization:International Consumer Protection And Enforcement Network \n - Product:Video Content \n - Country:China Emerging country with large population and growing disposable income.\n - Organization:Federal Trade Commission \n - Organization:Federal_Trade_Commission Regulates online advertising and the security of consumers’ personal information in the U.S.\n relationships:\n - Organization:Amazon COMPETITOR Organization:Ebay\n - Organization:Ebay COMPETES_WITH Organization:Amazon\n - Organization:Amazon COMPETES_WITH Organization:Ebay\n - Organization:Amazon COMPETITOR Organization:Barnes And Noble\n - Organization:Barnes And Noble COMPETES_WITH Organization:Amazon\n - Organization:Amazon COMPETES_WITH Organization:Barnes And Noble\n - Organization:Amazon COMPETITOR Organization:Wal-Mart\n - Organization:Amazon COMPETES_WITH Organization:Wal-Mart\n - Organization:Amazon BENEFIT Activity:Online Shopping\n - Concept:E-Commerce ENABLES Activity:Online Shopping\n - Organization:Amazon OPPORTUNITY Country:India\n - Organization:International Consumer Protection And Enforcement Network SUPPORTS Organization:Amazon\n - Organization:Amazon INVESTS_IN Product:Video Content\n - Organization:Amazon OPPORTUNITY Country:China\n - Organization:Federal Trade Commission REGULATES Organization:Amazon\n - Organization:Federal_Trade_Commission REGULATES Electronic_Commerce_Firms\n\nDocument end\n""]","In 2012, Amazon's Elastic Block Storage (EBS) service faced several downtimes due to electric outages. The main problem originated from Amazon's U.S. East data center in Virginia, which is the biggest and oldest data center and has been causing outage issues. These server crashes brought inconvenience and discomfort to the customers who use the website regularly. The company needed to do major upgrades on the U.S. East data center to prevent the services from going down in the future.",simple,0.0,0.0,0.0,0.9507036338911249,0.733409899743567 +What issues did Amazon's Elastic Block Storage (EBS) service face in 2012 and how did it affect the company?,graph+vector,"Amazon's Elastic Block Storage (EBS) service faced downtime in 2012 due to an electric outage at the U.S. East data center in Virginia, which is the largest and oldest data center for Amazon. This outage caused inconvenience and discomfort to customers who regularly used the website. The company had to undertake major upgrades on the U.S. East data center to prevent future service disruptions. Additionally, the increased expenditures on services like Kindle and Cloud prompted Amazon to plan a reduction in investments in these initiatives to focus on new projects generating more revenue and reflecting the company's value.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: Text Content:\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: Text Content:\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER\nDocument end\n']","In 2012, Amazon's Elastic Block Storage (EBS) service faced several downtimes due to electric outages. The main problem originated from Amazon's U.S. East data center in Virginia, which is the biggest and oldest data center and has been causing outage issues. These server crashes brought inconvenience and discomfort to the customers who use the website regularly. The company needed to do major upgrades on the U.S. East data center to prevent the services from going down in the future.",simple,0.9999999999,1.0,1.0,0.9240689240406725,0.8452230921841888 +What issues did Amazon's Elastic Block Storage (EBS) service face in 2012 and how did it affect the company?,graph+vector+fulltext,"Amazon's Elastic Block Storage (EBS) service faced downtime in 2012 due to an electric outage at the U.S. East data center in Virginia, which is the largest and oldest data center for Amazon. This outage caused inconvenience and discomfort for customers who regularly used the website. The company had to undertake major upgrades to prevent future service disruptions. Additionally, the increased expenditures on services like Kindle and Cloud prompted Amazon to plan a reduction in investments in these initiatives to focus on projects generating more revenue and reflecting the company's value.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: Text Content:\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: Text Content:\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER\nDocument end\n']","In 2012, Amazon's Elastic Block Storage (EBS) service faced several downtimes due to electric outages. The main problem originated from Amazon's U.S. East data center in Virginia, which is the biggest and oldest data center and has been causing outage issues. These server crashes brought inconvenience and discomfort to the customers who use the website regularly. The company needed to do major upgrades on the U.S. East data center to prevent the services from going down in the future.",simple,0.9999999999,1.0,1.0,0.9266902888856899,0.8449677841574839 +How does the integrated focused cost leadership strategy help competitors compete with Amazon in the book industry?,vector,"The integrated focused cost leadership strategy helps competitors in the book industry target price-sensitive consumers by providing books that are not readily available at a lower price. By focusing on cost leadership and differentiation simultaneously, competitors like Barnes and Noble aim to increase profitability, gain market share, and offer a wide variety of products to compete against Amazon. This strategy allows them to cater to a specific market segment effectively and differentiate themselves from Amazon's offerings.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: \t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n\t\r \xa0 0 BUS 478: Seminar on Business Strategy SYNOPSIS PROJECT: AMAZON.COM Group G Group Members: Tristan Landrecht Jessica Zhang John Chen Jin Can Chen Jae Kim \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: \t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n\t\r \xa0 0 BUS 478: Seminar on Business Strategy SYNOPSIS PROJECT: AMAZON.COM Group G Group Members: Tristan Landrecht Jessica Zhang John Chen Jin Can Chen Jae Kim \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\nDocument end\n']",The integrated focused cost leadership/differentiation strategy helps competitors compete with Amazon in the book industry by targeting price-sensitive consumers and providing books that are not readily or commonly available at a less expensive price.,simple,0.9999999999,1.0,0.75,0.9797332685421422,0.8178116358805732 +How does the integrated focused cost leadership strategy help competitors compete with Amazon in the book industry?,fulltext,"The integrated focused cost leadership strategy helps competitors in the book industry target price-sensitive consumers by providing books that are not readily available at a lower price. By focusing on cost leadership and differentiation simultaneously, competitors like Barnes and Noble aim to increase profitability, gain market share, and offer a wide variety of products to compete against Amazon. This strategy allows them to attract customers looking for affordable options while also providing unique offerings not commonly found elsewhere, thus creating a competitive edge in the market.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: \t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n\t\r \xa0 0 BUS 478: Seminar on Business Strategy SYNOPSIS PROJECT: AMAZON.COM Group G Group Members: Tristan Landrecht Jessica Zhang John Chen Jin Can Chen Jae Kim \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: \t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n\t\r \xa0 0 BUS 478: Seminar on Business Strategy SYNOPSIS PROJECT: AMAZON.COM Group G Group Members: Tristan Landrecht Jessica Zhang John Chen Jin Can Chen Jae Kim \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \nDocument end\n']",The integrated focused cost leadership/differentiation strategy helps competitors compete with Amazon in the book industry by targeting price-sensitive consumers and providing books that are not readily or commonly available at a less expensive price.,simple,0.9999999999,1.0,0.8888888888888888,0.9797517766983894,0.7761902121267035 +How does the integrated focused cost leadership strategy help competitors compete with Amazon in the book industry?,entity search+vector,"The integrated focused cost leadership strategy helps competitors like Barnes and Noble compete with Amazon in the book industry by allowing them to offer competitive pricing while maintaining a differentiation focus. This strategy enables companies to provide cost-effective products and services tailored to specific market segments, attracting customers seeking both value and unique offerings. By combining cost leadership with differentiation, competitors can address the bargaining power of buyers effectively, offering a compelling value proposition that can challenge Amazon's market dominance in the book industry.","[""Document start\nThis Document belongs to the source unknown\nContent: chunks:\n- providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n- \t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n- since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \ncommunities:\n- Amazon.com, founded in 1993 by Jeff Benzos, initially started as an online bookstore. Over the years, it has grown into a massive retail enterprise valued at $48 billion, offering products across more than forty categories. The company experienced significant growth momentum during the Dot-Com Bubble. Jeff Benzos, the founder, played a pivotal role in its development and expansion.\n- Jin Can Chen, Jae Kim, Jessica Zhang, John Chen, and Tristan Landrecht are all members of the course Bus 478, which is a seminar on business strategy. They are part of a group within this course, indicating a collaborative or team-based component to the class.\n- Amazon is a rapidly growing multinational e-commerce retailer based in America with a significant international presence. It faces competition from major organizations such as eBay, Barnes and Noble, and Wal-Mart. eBay and Barnes and Noble are noted for their product breadth and geographic market coverage, while Wal-Mart is recognized as the world's largest retail chain, employing a cost leadership strategy.\n\nAmazon competes with eBay, which utilizes both cost leadership and differentiation strategies. Barnes and Noble also competes with Amazon, employing an integrated focused cost leadership/differentiation strategy. Wal-Mart, another competitor, uses a cost leadership approach.\n\nAmazon is actively investing in various technologies and products, including video content, cloud services, and its Kindle product. It utilizes technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations. The company has also released a smartphone app and is located at the U.S. East Data Center.\n\nAmazon sees opportunities in emerging markets like China, which has a large population and growing disposable income. It is focused on capturing the global market and has invested in distribution centers to support this goal. The company discloses information about online sales taxes and is regulated by the Federal Trade Commission. Additionally, it receives support from the International Consumer Protection and Enforcement Network.\nrelationships:\n- Amazon COMPETITOR Barnes And Noble\n- Amazon COMPETES_WITH Barnes And Noble\n- Barnes And Noble USES Integrated Focused Cost Leadership/Differentiation\n- Barnes And Noble COMPETES_WITH Amazon\n- Bus 478 PROJECT Amazon.Com\nentities:\n- Integrated Focused Cost Leadership/Differentiation \n- Cost Leadership \n- Organization:Amazon Fastest-growing, multinational e-commerce retailer in America with international presence.\n- Company:Amazon.Com Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.\n- Organization:Barnes And Noble Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.\n- Electronic_Commerce_Firms \n- Course:Bus 478 Seminar on Business Strategy\n- Concept:Bargaining_Power_Of_Buyers High because customers can choose among numerous online stores for the lowest price.\n- Concept:E-Commerce \n- Organization:Morgan Grenfell Asset Management \noutside:\n nodes:\n - Organization:Ebay Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.\n - Organization:Wal-Mart World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.\n - Person:Jessica Zhang \n - Person:John Chen \n - Activity:Online Shopping \n - Person:Tristan Landrecht \n - Person:Jae Kim \n - Person:Jin Can Chen \n - Country:China Emerging country with large population and growing disposable income.\n - Country:India Emerging country with large population and growing disposable income.\n relationships:\n - Organization:Ebay USES Cost Leadership\n - Organization:Amazon COMPETITOR Organization:Ebay\n - Organization:Ebay COMPETES_WITH Organization:Amazon\n - Organization:Amazon COMPETES_WITH Organization:Ebay\n - Organization:Wal-Mart USES Cost Leadership\n - Organization:Amazon COMPETITOR Organization:Wal-Mart\n - Organization:Amazon COMPETES_WITH Organization:Wal-Mart\n - Person:Jessica Zhang MEMBER Course:Bus 478\n - Course:Bus 478 GROUP_MEMBER Person:Jessica Zhang\n - Person:John Chen MEMBER Course:Bus 478\n - Course:Bus 478 GROUP_MEMBER Person:John Chen\n - Organization:Amazon BENEFIT Activity:Online Shopping\n - Concept:E-Commerce ENABLES Activity:Online Shopping\n - Person:Tristan Landrecht MEMBER Course:Bus 478\n - Course:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\n - Person:Jae Kim MEMBER Course:Bus 478\n - Course:Bus 478 GROUP_MEMBER Person:Jae Kim\n - Person:Jin Can Chen MEMBER Course:Bus 478\n - Course:Bus 478 GROUP_MEMBER Person:Jin Can Chen\n - Organization:Amazon OPPORTUNITY Country:China\n - Organization:Amazon OPPORTUNITY Country:India\n\nDocument end\n""]",The integrated focused cost leadership/differentiation strategy helps competitors compete with Amazon in the book industry by targeting price-sensitive consumers and providing books that are not readily or commonly available at a less expensive price.,simple,0.9999999999,0.0,1.0,0.9831685457786773,0.6700925458407849 +How does the integrated focused cost leadership strategy help competitors compete with Amazon in the book industry?,graph+vector,"The integrated focused cost leadership strategy helps competitors in the book industry target price-sensitive consumers by providing books that are not readily available at a lower price. This strategy allows competitors to offer unique products and services while maintaining cost efficiency, enabling them to compete with Amazon by attracting customers looking for affordable options and niche book selections.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: Text Content:\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n\t\r \xa0 0 BUS 478: Seminar on Business Strategy SYNOPSIS PROJECT: AMAZON.COM Group G Group Members: Tristan Landrecht Jessica Zhang John Chen Jin Can Chen Jae Kim \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Shivam Dube PLAYER Country:India\nPerson:Tristan Landrecht MEMBER Course:Bus 478\nPerson:Virat Kohli PLAYER Country:India\nPerson:Yashasvi Jaiswal PLAYER Country:India\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: Text Content:\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n\t\r \xa0 0 BUS 478: Seminar on Business Strategy SYNOPSIS PROJECT: AMAZON.COM Group G Group Members: Tristan Landrecht Jessica Zhang John Chen Jin Can Chen Jae Kim \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Shivam Dube PLAYER Country:India\nPerson:Tristan Landrecht MEMBER Course:Bus 478\nPerson:Virat Kohli PLAYER Country:India\nPerson:Yashasvi Jaiswal PLAYER Country:India\nDocument end\n']",The integrated focused cost leadership/differentiation strategy helps competitors compete with Amazon in the book industry by targeting price-sensitive consumers and providing books that are not readily or commonly available at a less expensive price.,simple,0.9999999999,1.0,0.42857142857142855,0.9894747362032149,0.7453209000480977 +How does the integrated focused cost leadership strategy help competitors compete with Amazon in the book industry?,graph+vector+fulltext,"The integrated focused cost leadership strategy helps competitors in the book industry target price-sensitive consumers by providing books that are not readily available at a lower price. By combining cost leadership with differentiation, competitors can offer unique products at competitive prices, aiming to increase profitability and gain market share. This strategy allows them to compete with Amazon by offering a variety of products and services that cater to specific consumer needs while maintaining cost efficiency.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: Text Content:\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n\t\r \xa0 0 BUS 478: Seminar on Business Strategy SYNOPSIS PROJECT: AMAZON.COM Group G Group Members: Tristan Landrecht Jessica Zhang John Chen Jin Can Chen Jae Kim \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Shivam Dube PLAYER Country:India\nPerson:Tristan Landrecht MEMBER Course:Bus 478\nPerson:Virat Kohli PLAYER Country:India\nPerson:Yashasvi Jaiswal PLAYER Country:India\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: Text Content:\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n\t\r \xa0 0 BUS 478: Seminar on Business Strategy SYNOPSIS PROJECT: AMAZON.COM Group G Group Members: Tristan Landrecht Jessica Zhang John Chen Jin Can Chen Jae Kim \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Shivam Dube PLAYER Country:India\nPerson:Tristan Landrecht MEMBER Course:Bus 478\nPerson:Virat Kohli PLAYER Country:India\nPerson:Yashasvi Jaiswal PLAYER Country:India\nDocument end\n']",The integrated focused cost leadership/differentiation strategy helps competitors compete with Amazon in the book industry by targeting price-sensitive consumers and providing books that are not readily or commonly available at a less expensive price.,simple,0.9999999999,1.0,1.0,0.9894149592194954,0.6202041786772748 +How does the integrated focused cost leadership strategy help competitors compete with Amazon in the book industry?,global search+vector+fulltext,"The integrated focused cost leadership strategy helps competitors like Barnes and Noble compete with Amazon in the book industry by allowing them to offer a unique value proposition. By combining cost leadership with differentiation, Barnes and Noble can focus on specific market segments or niches where they can provide distinct products or services at competitive prices. This strategy enables them to target specific customer needs effectively while maintaining cost efficiency, thereby creating a competitive advantage against Amazon's broader market approach.","[""Document start\nThis Document belongs to the source unknown\nContent: Amazon is a rapidly growing multinational e-commerce retailer based in America with a significant international presence. It faces competition from major organizations such as eBay, Barnes and Noble, and Wal-Mart. eBay and Barnes and Noble are noted for their product breadth and geographic market coverage, while Wal-Mart is recognized as the world's largest retail chain, employing a cost leadership strategy.\n\nAmazon competes with eBay, which utilizes both cost leadership and differentiation strategies. Barnes and Noble also competes with Amazon, employing an integrated focused cost leadership/differentiation strategy. Wal-Mart, another competitor, uses a cost leadership approach.\n\nAmazon is actively investing in various technologies and products, including video content, cloud services, and its Kindle product. It utilizes technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations. The company has also released a smartphone app and is located at the U.S. East Data Center.\n\nAmazon sees opportunities in emerging markets like China, which has a large population and growing disposable income. It is focused on capturing the global market and has invested in distribution centers to support this goal. The company discloses information about online sales taxes and is regulated by the Federal Trade Commission. Additionally, it receives support from the International Consumer Protection and Enforcement Network.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offers a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, being regulated by the Federal Trade Commission and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nThe community consists of a group of individuals, Jin Can Chen, Jae Kim, Jessica Zhang, John Chen, and Tristan Landrecht, who are enrolled in Bus 478, a seminar focused on business strategy. This course involves a collaborative or team-based approach, suggesting that these members work closely together on projects or discussions related to business strategy. Additionally, the community is linked to Amazon.com, a company founded in 1993 by Jeff Benzos. Originally an online bookstore, Amazon has evolved into a vast retail enterprise valued at $48 billion, offering a wide range of products across more than forty categories. The company saw substantial growth during the Dot-Com Bubble, with Jeff Benzos playing a crucial role in its expansion and success. This connection to Amazon may indicate that the course or group discussions could involve case studies or strategic analyses of Amazon's business model and growth trajectory.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offers a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, regulated by the Federal Trade Commission, and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offer a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, regulated by the Federal Trade Commission, and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nAmazon.com, founded in 1993 by Jeff Benzos, initially started as an online bookstore. Over the years, it has grown into a massive retail enterprise valued at $48 billion, offering products across more than forty categories. The company experienced significant growth momentum during the Dot-Com Bubble. Jeff Benzos, the founder, played a pivotal role in its development and expansion.\n----\nThe community consists of individuals and entities connected through educational and business endeavors. Jin Can Chen, Jae Kim, Jessica Zhang, John Chen, and Tristan Landrecht are all participants in Bus 478, a seminar focused on business strategy, which emphasizes teamwork and collaboration. This educational setting likely fosters skills relevant to business growth and strategy, akin to those demonstrated by Amazon.com. Founded in 1993 by Jeff Benzos, Amazon began as an online bookstore and evolved into a vast retail empire valued at $48 billion, offering a diverse range of products across more than forty categories. The company's significant expansion, particularly during the Dot-Com Bubble, highlights the importance of strategic business planning and leadership, as exemplified by Benzos' pivotal role in its success. This connection between the educational focus of Bus 478 and the business strategies employed by Amazon underscores the relevance of strategic thinking in both academic and real-world business contexts.\n----\nThe community consists of individuals and entities connected through educational and business endeavors. Jin Can Chen, Jae Kim, Jessica Zhang, John Chen, and Tristan Landrecht are all participants in Bus 478, a seminar focused on business strategy, which emphasizes teamwork and collaboration. This educational setting likely fosters skills relevant to business growth and strategy, akin to those demonstrated by Amazon.com. Founded in 1993 by Jeff Benzos, Amazon began as an online bookstore and evolved into a vast retail empire valued at $48 billion, offering a diverse range of products across more than forty categories. The company's significant expansion, particularly during the Dot-Com Bubble, highlights the importance of strategic business planning and leadership, as exemplified by Benzos' pivotal role in its success. This connection between the educational focus of Bus 478 and the business strategies employed by Amazon underscores the relevance of strategic thinking in both academic and real-world business contexts.\n----\nJin Can Chen, Jae Kim, Jessica Zhang, John Chen, and Tristan Landrecht are all members of the course Bus 478, which is a seminar on business strategy. They are part of a group within this course, indicating a collaborative or team-based component to the class.\n----\nThe Etnow Poll event projected that InterGlobe Aviation, a prominent player in the aviation industry, was expected to announce a financial loss of Rs 660 crore. This forecast highlights the financial challenges faced by the company, possibly due to factors such as fluctuating fuel prices, operational costs, or market conditions impacting the aviation sector. The anticipation of such a significant loss underscores the need for strategic adjustments and financial planning to navigate the economic pressures within the industry.\nDocument end\n""]",The integrated focused cost leadership/differentiation strategy helps competitors compete with Amazon in the book industry by targeting price-sensitive consumers and providing books that are not readily or commonly available at a less expensive price.,simple,0.9999999999,0.0,0.25,0.9739451880358826,0.6658696336624164 +What is the competitive strategy of Barnes and Noble in the e-commerce industry?,vector,"Barnes and Noble, as America's largest book retailer, employs an integrated focused cost leadership/differentiation strategy in the e-commerce industry. They target price-sensitive consumers by offering books that are not readily available at a lower price. This strategy allows them to compete with Amazon by providing unique products and competitive pricing to gain market share in the book industry.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: \t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: \t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\nDocument end\n']",The answer to given question is not present in context,simple,0.0,1.0,1.0,0.9732296166055742,0.17532420230388426 +What is the competitive strategy of Barnes and Noble in the e-commerce industry?,fulltext,"Barnes and Noble, as America's largest book retailer, employs an integrated focused cost leadership/differentiation strategy in the e-commerce industry. They target price-sensitive consumers by offering books that are not readily available at a lower price. This strategy allows them to compete with Amazon by providing unique products and competitive pricing to gain market share in the book industry.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: \t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: \t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\nDocument end\n']",The answer to given question is not present in context,simple,0.9999999999,1.0,0.7142857142857143,0.9731916159213346,0.17537330046954663 +What is the competitive strategy of Barnes and Noble in the e-commerce industry?,entity search+vector,"Barnes and Noble employs an integrated focused cost leadership/differentiation strategy in the e-commerce industry. This strategy involves offering unique products or services while also maintaining competitive pricing to attract customers. By combining elements of cost leadership and differentiation, Barnes and Noble aims to stand out from competitors like Amazon and provide value to its customers in the online retail market.","[""Document start\nThis Document belongs to the source unknown\nContent: chunks:\n- \t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n- Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers. Demographic As the world’s population is aging rapidly, baby boomers are moving towards retirement so that they will have weaker purchasing power. Thus, generation X and Y have become companies’ target markets for product selling. These generations are technologically adept and tend to engage more in online purchasing. Based on a survey, 62 percent of Generation Y liked to purchase things online, as compared to 32 percent of those aged older than 50. Organizations \n- \t\r \xa0 3 online payment methods such as online banking and PayPal create more convenience in purchase transactions, which in turn enhances customers’ online shopping experience. Also, the invention of electronic devices such as smartphones deliver easy and convenient transaction processes, further facilitating online shopping. For instance, Amazon recently released a smartphone app for their Kindle services, allowing users to conveniently access the online sales platform and review products before purchasing. In the future, the use of 3D virtual technology to market products will also take online shopping to new heights. Political/Legal In the modern day environment, firms must be cautious when they deal with international policies on online distribution. In the U.S., electronic commerce firms are regulated by the Federal Trade Commission, which regulates online advertising and the security of consumers’ personal information. On the other hand, International Consumer Protection and Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions \ncommunities:\n- Neo4j is a comprehensive graph database management system that offers a wide range of products, services, and resources to support graph data science and related applications. It provides various deployment options, including Cloud Managed Services, Self-Hosted, and Graph-As-A-Service, with Amazon AWS as a cloud provider. Neo4j's offerings include the Neo4j Graph Data Science product, Neo4j GraphQL Library, Neo4j Workspace, Neo4j Bloom visualization tool, Neo4j Developer Tools, and Neo4j Data Connectors, all of which are integral parts of the Neo4j ecosystem.\n\nThe organization supports learning and development through resources like Graphacademy, which offers free online courses and certifications, and the Neo4j Blog for daily insights. It also provides a Resource Library with white papers and data sheets, Case Studies showcasing customer success stories, and Executive Insights on graph technology.\n\nNeo4j hosts various events, including the Neo4j Events Hub for live and on-demand training, webinars, and demos, the quarterly online conference Connections, and the global Graphsummit tour. The Cypher query language is a key technology used within Neo4j for exploring and manipulating graph data.\n\nAdditionally, Neo4j includes a company structure with information about its culture, diversity, leadership, and partnerships, offering opportunities to find or become a partner through its Partner Portal.\n- Amazon is a rapidly growing multinational e-commerce retailer based in America with a significant international presence. It faces competition from major organizations such as eBay, Barnes and Noble, and Wal-Mart. eBay and Barnes and Noble are noted for their product breadth and geographic market coverage, while Wal-Mart is recognized as the world's largest retail chain, employing a cost leadership strategy.\n\nAmazon competes with eBay, which utilizes both cost leadership and differentiation strategies. Barnes and Noble also competes with Amazon, employing an integrated focused cost leadership/differentiation strategy. Wal-Mart, another competitor, uses a cost leadership approach.\n\nAmazon is actively investing in various technologies and products, including video content, cloud services, and its Kindle product. It utilizes technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations. The company has also released a smartphone app and is located at the U.S. East Data Center.\n\nAmazon sees opportunities in emerging markets like China, which has a large population and growing disposable income. It is focused on capturing the global market and has invested in distribution centers to support this goal. The company discloses information about online sales taxes and is regulated by the Federal Trade Commission. Additionally, it receives support from the International Consumer Protection and Enforcement Network.\n- Amazon is a rapidly growing multinational e-commerce retailer based in America with a significant international presence. It faces competition from major organizations such as eBay, Barnes and Noble, and Wal-Mart. eBay and Barnes and Noble are noted for their product breadth and geographic market coverage, while Wal-Mart is recognized as the world's largest retail chain, employing a cost leadership strategy.\n\nAmazon competes with eBay, which utilizes both cost leadership and differentiation strategies. Barnes and Noble also competes with Amazon, employing an integrated focused cost leadership/differentiation strategy. Wal-Mart, another competitor, uses a cost leadership approach.\n\nAmazon is actively investing in various technologies and products, including video content, cloud services, and its Kindle product. It utilizes technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations. The company has also released a smartphone app and is located at the U.S. East Data Center.\n\nAmazon sees opportunities in emerging markets like China, which has a large population and growing disposable income. It is focused on capturing the global market and has invested in distribution centers to support this goal. The company discloses information about online sales taxes and is regulated by the Federal Trade Commission. Additionally, it receives support from the International Consumer Protection and Enforcement Network.\nrelationships:\n- E-Commerce ENABLES Online Shopping\n- Barnes And Noble COMPETES_WITH Amazon\n- Amazon COMPETITOR Barnes And Noble\n- Amazon COMPETES_WITH Barnes And Noble\n- Amazon BENEFIT Online Shopping\nentities:\n- Concept:E-Commerce \n- Electronic_Commerce_Firms \n- Organization:Barnes And Noble Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.\n- Resource:Case Studies Customer success stories across industries.\n- Activity:Online Shopping \n- Online_Shopping_Experience \n- Online_Shopping \n- Organization:Amazon Fastest-growing, multinational e-commerce retailer in America with international presence.\n- Online_Purchasing \n- Use case:Industries & Use Cases Fraud detection, knowledge graphs, financial services, and more\noutside:\n nodes:\n - Organization:Ebay Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.\n - Organization:Wal-Mart World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.\n - Organization:Neo4J A graph database management system.\n - Concept:Web Security \n - Group:Consumers \n - Group:Baby Boomers \n - Technology:Online Payment Methods \n - Technology:3D Virtual Technology \n - Technology:Smartphones \n - Concept:Modern Tech Support \n relationships:\n - Organization:Amazon COMPETITOR Organization:Ebay\n - Organization:Ebay COMPETES_WITH Organization:Amazon\n - Organization:Amazon COMPETES_WITH Organization:Ebay\n - Organization:Amazon COMPETITOR Organization:Wal-Mart\n - Organization:Amazon COMPETES_WITH Organization:Wal-Mart\n - Organization:Neo4J PROVIDES Resource:Case Studies\n - Concept:Web Security FACILITATES Activity:Online Shopping\n - Group:Consumers PREFERENCE Activity:Online Shopping\n - Group:Baby Boomers LESS_INVOLVED Activity:Online Shopping\n - Technology:Online Payment Methods ENHANCES Activity:Online Shopping\n - Technology:3D Virtual Technology FUTURE Activity:Online Shopping\n - Technology:Smartphones FACILITATES Activity:Online Shopping\n - Concept:Modern Tech Support FACILITATES Activity:Online Shopping\n\nDocument end\n""]",The answer to given question is not present in context,simple,0.0,1.0,0.2,0.9732296166055742,0.17267541840546935 +What is the competitive strategy of Barnes and Noble in the e-commerce industry?,graph+vector,"Barnes and Noble, a major competitor of Amazon in the e-commerce industry, employs an integrated focused cost leadership/differentiation strategy. This strategy targets price-sensitive consumers by offering books that are not readily available at a lower price. By combining elements of cost leadership and differentiation, Barnes and Noble aims to increase profitability and compete effectively with Amazon for market share in the book industry.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: Text Content:\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Sales_Taxes\n:Smartphone_App\nActivity:Online Shopping\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nConcept:Modern Tech Support\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nConcept:Modern Tech Support FACILITATES Activity:Online Shopping\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Sh\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: Text Content:\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Sales_Taxes\n:Smartphone_App\nActivity:Online Shopping\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nConcept:Modern Tech Support\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nConcept:Modern Tech Support FACILITATES Activity:Online Shopping\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Sh\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon 1.pdf\nContent: ivam Dube PLAYER Country:India\nPerson:Tristan Landrecht MEMBER Course:Bus 478\nPerson:Virat Kohli PLAYER Country:India\nPerson:Yashasvi Jaiswal PLAYER Country:India\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: ivam Dube PLAYER Country:India\nPerson:Tristan Landrecht MEMBER Course:Bus 478\nPerson:Virat Kohli PLAYER Country:India\nPerson:Yashasvi Jaiswal PLAYER Country:India\nDocument end\n']",The answer to given question is not present in context,simple,0.9999999999,1.0,1.0,0.9507042440470773,0.17496629219404303 +What is the competitive strategy of Barnes and Noble in the e-commerce industry?,graph+vector+fulltext,"Barnes and Noble employs an integrated focused cost leadership/differentiation strategy in the e-commerce industry. This strategy targets price-sensitive consumers by offering books that are not readily available at a lower price. By combining elements of cost leadership and differentiation, Barnes and Noble competes intensively with Amazon for market share in the book industry.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: Text Content:\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Sales_Taxes\n:Smartphone_App\nActivity:Online Shopping\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nConcept:Modern Tech Support\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nConcept:Modern Tech Support FACILITATES Activity:Online Shopping\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Sh\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: Text Content:\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Sales_Taxes\n:Smartphone_App\nActivity:Online Shopping\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nConcept:Modern Tech Support\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nConcept:Modern Tech Support FACILITATES Activity:Online Shopping\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Sh\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon 1.pdf\nContent: ivam Dube PLAYER Country:India\nPerson:Tristan Landrecht MEMBER Course:Bus 478\nPerson:Virat Kohli PLAYER Country:India\nPerson:Yashasvi Jaiswal PLAYER Country:India\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: ivam Dube PLAYER Country:India\nPerson:Tristan Landrecht MEMBER Course:Bus 478\nPerson:Virat Kohli PLAYER Country:India\nPerson:Yashasvi Jaiswal PLAYER Country:India\nDocument end\n']",The answer to given question is not present in context,simple,0.9999999999,1.0,1.0,0.973263566345624,0.17508211810613783 +What is the competitive strategy of Barnes and Noble in the e-commerce industry?,global search+vector+fulltext,"Barnes and Noble in the e-commerce industry employs an integrated focused cost leadership/differentiation strategy. This strategy combines elements of cost leadership and differentiation to set itself apart from competitors like Amazon and eBay. By focusing on cost efficiency while also offering unique and differentiated products or services, Barnes and Noble aims to carve out a competitive position in the market.","[""Document start\nThis Document belongs to the source unknown\nContent: Amazon is a rapidly growing multinational e-commerce retailer based in America with a significant international presence. It faces competition from major organizations such as eBay, Barnes and Noble, and Wal-Mart. eBay and Barnes and Noble are noted for their product breadth and geographic market coverage, while Wal-Mart is recognized as the world's largest retail chain, employing a cost leadership strategy.\n\nAmazon competes with eBay, which utilizes both cost leadership and differentiation strategies. Barnes and Noble also competes with Amazon, employing an integrated focused cost leadership/differentiation strategy. Wal-Mart, another competitor, uses a cost leadership approach.\n\nAmazon is actively investing in various technologies and products, including video content, cloud services, and its Kindle product. It utilizes technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations. The company has also released a smartphone app and is located at the U.S. East Data Center.\n\nAmazon sees opportunities in emerging markets like China, which has a large population and growing disposable income. It is focused on capturing the global market and has invested in distribution centers to support this goal. The company discloses information about online sales taxes and is regulated by the Federal Trade Commission. Additionally, it receives support from the International Consumer Protection and Enforcement Network.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offers a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, regulated by the Federal Trade Commission, and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offer a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, regulated by the Federal Trade Commission, and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offers a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, being regulated by the Federal Trade Commission and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nThe community consists of a group of individuals, Jin Can Chen, Jae Kim, Jessica Zhang, John Chen, and Tristan Landrecht, who are enrolled in Bus 478, a seminar focused on business strategy. This course involves a collaborative or team-based approach, suggesting that these members work closely together on projects or discussions related to business strategy. Additionally, the community is linked to Amazon.com, a company founded in 1993 by Jeff Benzos. Originally an online bookstore, Amazon has evolved into a vast retail enterprise valued at $48 billion, offering a wide range of products across more than forty categories. The company saw substantial growth during the Dot-Com Bubble, with Jeff Benzos playing a crucial role in its expansion and success. This connection to Amazon may indicate that the course or group discussions could involve case studies or strategic analyses of Amazon's business model and growth trajectory.\n----\nThe community consists of individuals and entities connected through educational and business endeavors. Jin Can Chen, Jae Kim, Jessica Zhang, John Chen, and Tristan Landrecht are all participants in Bus 478, a seminar focused on business strategy, which emphasizes teamwork and collaboration. This educational setting likely fosters skills relevant to business growth and strategy, akin to those demonstrated by Amazon.com. Founded in 1993 by Jeff Benzos, Amazon began as an online bookstore and evolved into a vast retail empire valued at $48 billion, offering a diverse range of products across more than forty categories. The company's significant expansion, particularly during the Dot-Com Bubble, highlights the importance of strategic business planning and leadership, as exemplified by Benzos' pivotal role in its success. This connection between the educational focus of Bus 478 and the business strategies employed by Amazon underscores the relevance of strategic thinking in both academic and real-world business contexts.\n----\nThe community consists of individuals and entities connected through educational and business endeavors. Jin Can Chen, Jae Kim, Jessica Zhang, John Chen, and Tristan Landrecht are all participants in Bus 478, a seminar focused on business strategy, which emphasizes teamwork and collaboration. This educational setting likely fosters skills relevant to business growth and strategy, akin to those demonstrated by Amazon.com. Founded in 1993 by Jeff Benzos, Amazon began as an online bookstore and evolved into a vast retail empire valued at $48 billion, offering a diverse range of products across more than forty categories. The company's significant expansion, particularly during the Dot-Com Bubble, highlights the importance of strategic business planning and leadership, as exemplified by Benzos' pivotal role in its success. This connection between the educational focus of Bus 478 and the business strategies employed by Amazon underscores the relevance of strategic thinking in both academic and real-world business contexts.\n----\nAmazon.com, founded in 1993 by Jeff Benzos, initially started as an online bookstore. Over the years, it has grown into a massive retail enterprise valued at $48 billion, offering products across more than forty categories. The company experienced significant growth momentum during the Dot-Com Bubble. Jeff Benzos, the founder, played a pivotal role in its development and expansion.\n----\nThe integration of 3D virtual technology is revolutionizing the online shopping experience, offering a more immersive and engaging way for consumers to explore products. This technological advancement is complemented by the widespread use of electronic devices, particularly smartphones, which streamline and simplify the transaction process, making online shopping more accessible and convenient. Furthermore, emerging markets, notably China and India, are poised for significant growth in the online shopping sector. These countries, characterized by their vast populations and rising disposable incomes, present lucrative opportunities for expansion and development in the e-commerce industry.\n----\nThe online shopping landscape is undergoing a transformative enhancement through the integration of 3D virtual technology, which aims to significantly elevate the consumer experience. This technological advancement is complemented by the widespread use of electronic devices, particularly smartphones, which are streamlining and simplifying transaction processes for online shoppers. Furthermore, emerging markets, notably China and India, are poised to play a pivotal role in the expansion of online shopping. These countries, characterized by their vast populations and rising disposable incomes, offer substantial opportunities for growth and development in the online retail sector.\nDocument end\n""]",The answer to given question is not present in context,simple,0.0,1.0,0.3333333333333333,0.9732296166055742,0.17212539693538745 +Why should online retailers like Amazon be careful about disclosing online sales taxes in their advertisements?,vector,Online retailers like Amazon should be cautious about disclosing online sales taxes in their advertisements because different sales tax regulations across countries can lead to customer confusion. Failure to accurately disclose these taxes can result in customer dissatisfaction and potential legal issues. Transparency in online sales tax information is crucial to maintain trust with customers and ensure compliance with international policies on online distribution.,"['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers. Demographic As the world’s population is aging rapidly, baby boomers are moving towards retirement so that they will have weaker purchasing power. Thus, generation X and Y have become companies’ target markets for product selling. These generations are technologically adept and tend to engage more in online purchasing. Based on a survey, 62 percent of Generation Y liked to purchase things online, as compared to 32 percent of those aged older than 50. Organizations \n----\n tanked, many people chose to migrate their shopping onto an online platform. In 2011, online sales actually increased by 11 percent despite what people imagined. The reason this has \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 3 online payment methods such as online banking and PayPal create more convenience in purchase transactions, which in turn enhances customers’ online shopping experience. Also, the invention of electronic devices such as smartphones deliver easy and convenient transaction processes, further facilitating online shopping. For instance, Amazon recently released a smartphone app for their Kindle services, allowing users to conveniently access the online sales platform and review products before purchasing. In the future, the use of 3D virtual technology to market products will also take online shopping to new heights. Political/Legal In the modern day environment, firms must be cautious when they deal with international policies on online distribution. In the U.S., electronic commerce firms are regulated by the Federal Trade Commission, which regulates online advertising and the security of consumers’ personal information. On the other hand, International Consumer Protection and Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers. Demographic As the world’s population is aging rapidly, baby boomers are moving towards retirement so that they will have weaker purchasing power. Thus, generation X and Y have become companies’ target markets for product selling. These generations are technologically adept and tend to engage more in online purchasing. Based on a survey, 62 percent of Generation Y liked to purchase things online, as compared to 32 percent of those aged older than 50. Organizations \n----\n tanked, many people chose to migrate their shopping onto an online platform. In 2011, online sales actually increased by 11 percent despite what people imagined. The reason this has \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 3 online payment methods such as online banking and PayPal create more convenience in purchase transactions, which in turn enhances customers’ online shopping experience. Also, the invention of electronic devices such as smartphones deliver easy and convenient transaction processes, further facilitating online shopping. For instance, Amazon recently released a smartphone app for their Kindle services, allowing users to conveniently access the online sales platform and review products before purchasing. In the future, the use of 3D virtual technology to market products will also take online shopping to new heights. Political/Legal In the modern day environment, firms must be cautious when they deal with international policies on online distribution. In the U.S., electronic commerce firms are regulated by the Federal Trade Commission, which regulates online advertising and the security of consumers’ personal information. On the other hand, International Consumer Protection and Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \nDocument end\n\n\nDocument start\nThis Document belongs to the source Alphabet_Q1_stock.pdf\nContent: $6.69 billion vs. $6.6 billion, according to StreetAccount. • Google Cloud revenue: $7.45 billion vs. $7.49 billion, according to StreetAccount. • Traffic acquisition costs (TAC): $11.72 billion vs. $11.78 billion, according to StreetAccount. Alphabets revenue rose 3% to $69.79 billion from $68 billion a year earlier, according to the earnings report. The company is mired in a multi-quarter stretch of low single-digit revenue growth after almost two decades of consistent and rapid expansion. With fears of a recession building since last year, advertisers have been reeling in online marketing budgets, wreaking havoc on Google, Facebook and others. \nDocument end\n']","Online retailers like Amazon should be careful about disclosing online sales taxes in their advertisements because different sales taxes can cause confusion to customers, especially in the context of cross-border transactions.",simple,0.9999999999,1.0,0.3333333333333333,0.9977437671677444,0.5751075168304566 +Why should online retailers like Amazon be careful about disclosing online sales taxes in their advertisements?,fulltext,"Online retailers like Amazon should be careful about disclosing online sales taxes in their advertisements because different sales tax regulations can vary between countries or regions. Failure to disclose these taxes can lead to customer confusion and dissatisfaction. Clear disclosure helps to maintain transparency and trust with customers, ensuring they are fully informed about the total cost of their purchases. This transparency is crucial for customer satisfaction and compliance with legal requirements in different jurisdictions.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers. Demographic As the world’s population is aging rapidly, baby boomers are moving towards retirement so that they will have weaker purchasing power. Thus, generation X and Y have become companies’ target markets for product selling. These generations are technologically adept and tend to engage more in online purchasing. Based on a survey, 62 percent of Generation Y liked to purchase things online, as compared to 32 percent of those aged older than 50. Organizations \n----\n tanked, many people chose to migrate their shopping onto an online platform. In 2011, online sales actually increased by 11 percent despite what people imagined. The reason this has \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 3 online payment methods such as online banking and PayPal create more convenience in purchase transactions, which in turn enhances customers’ online shopping experience. Also, the invention of electronic devices such as smartphones deliver easy and convenient transaction processes, further facilitating online shopping. For instance, Amazon recently released a smartphone app for their Kindle services, allowing users to conveniently access the online sales platform and review products before purchasing. In the future, the use of 3D virtual technology to market products will also take online shopping to new heights. Political/Legal In the modern day environment, firms must be cautious when they deal with international policies on online distribution. In the U.S., electronic commerce firms are regulated by the Federal Trade Commission, which regulates online advertising and the security of consumers’ personal information. On the other hand, International Consumer Protection and Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers. Demographic As the world’s population is aging rapidly, baby boomers are moving towards retirement so that they will have weaker purchasing power. Thus, generation X and Y have become companies’ target markets for product selling. These generations are technologically adept and tend to engage more in online purchasing. Based on a survey, 62 percent of Generation Y liked to purchase things online, as compared to 32 percent of those aged older than 50. Organizations \n----\n tanked, many people chose to migrate their shopping onto an online platform. In 2011, online sales actually increased by 11 percent despite what people imagined. The reason this has \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 3 online payment methods such as online banking and PayPal create more convenience in purchase transactions, which in turn enhances customers’ online shopping experience. Also, the invention of electronic devices such as smartphones deliver easy and convenient transaction processes, further facilitating online shopping. For instance, Amazon recently released a smartphone app for their Kindle services, allowing users to conveniently access the online sales platform and review products before purchasing. In the future, the use of 3D virtual technology to market products will also take online shopping to new heights. Political/Legal In the modern day environment, firms must be cautious when they deal with international policies on online distribution. In the U.S., electronic commerce firms are regulated by the Federal Trade Commission, which regulates online advertising and the security of consumers’ personal information. On the other hand, International Consumer Protection and Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \nDocument end\n\n\nDocument start\nThis Document belongs to the source Alphabet_Q1_stock.pdf\nContent: $6.69 billion vs. $6.6 billion, according to StreetAccount. • Google Cloud revenue: $7.45 billion vs. $7.49 billion, according to StreetAccount. • Traffic acquisition costs (TAC): $11.72 billion vs. $11.78 billion, according to StreetAccount. Alphabets revenue rose 3% to $69.79 billion from $68 billion a year earlier, according to the earnings report. The company is mired in a multi-quarter stretch of low single-digit revenue growth after almost two decades of consistent and rapid expansion. With fears of a recession building since last year, advertisers have been reeling in online marketing budgets, wreaking havoc on Google, Facebook and others. \nDocument end\n']","Online retailers like Amazon should be careful about disclosing online sales taxes in their advertisements because different sales taxes can cause confusion to customers, especially in the context of cross-border transactions.",simple,0.9999999999,1.0,0.7777777777777778,0.9999999999999997,0.9401644330221344 +Why should online retailers like Amazon be careful about disclosing online sales taxes in their advertisements?,entity search+vector,Online retailers like Amazon should be careful about disclosing online sales taxes in their advertisements because different sales tax rates can lead to customer confusion. Transparency in disclosing these taxes helps to avoid misunderstandings and ensures that customers are aware of the total cost of their purchases. Failure to disclose online sales taxes can result in customer dissatisfaction and potential legal issues related to misleading advertising practices.,"[""Document start\nThis Document belongs to the source unknown\nContent: chunks:\n- Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers. Demographic As the world’s population is aging rapidly, baby boomers are moving towards retirement so that they will have weaker purchasing power. Thus, generation X and Y have become companies’ target markets for product selling. These generations are technologically adept and tend to engage more in online purchasing. Based on a survey, 62 percent of Generation Y liked to purchase things online, as compared to 32 percent of those aged older than 50. Organizations \n- \t\r \xa0 3 online payment methods such as online banking and PayPal create more convenience in purchase transactions, which in turn enhances customers’ online shopping experience. Also, the invention of electronic devices such as smartphones deliver easy and convenient transaction processes, further facilitating online shopping. For instance, Amazon recently released a smartphone app for their Kindle services, allowing users to conveniently access the online sales platform and review products before purchasing. In the future, the use of 3D virtual technology to market products will also take online shopping to new heights. Political/Legal In the modern day environment, firms must be cautious when they deal with international policies on online distribution. In the U.S., electronic commerce firms are regulated by the Federal Trade Commission, which regulates online advertising and the security of consumers’ personal information. On the other hand, International Consumer Protection and Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions \n- providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \ncommunities:\n- Amazon is a rapidly growing multinational e-commerce retailer based in America with a significant international presence. It faces competition from major organizations such as eBay, Barnes and Noble, and Wal-Mart. eBay and Barnes and Noble are noted for their product breadth and geographic market coverage, while Wal-Mart is recognized as the world's largest retail chain, employing a cost leadership strategy.\n\nAmazon competes with eBay, which utilizes both cost leadership and differentiation strategies. Barnes and Noble also competes with Amazon, employing an integrated focused cost leadership/differentiation strategy. Wal-Mart, another competitor, uses a cost leadership approach.\n\nAmazon is actively investing in various technologies and products, including video content, cloud services, and its Kindle product. It utilizes technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations. The company has also released a smartphone app and is located at the U.S. East Data Center.\n\nAmazon sees opportunities in emerging markets like China, which has a large population and growing disposable income. It is focused on capturing the global market and has invested in distribution centers to support this goal. The company discloses information about online sales taxes and is regulated by the Federal Trade Commission. Additionally, it receives support from the International Consumer Protection and Enforcement Network.\n- Generation X and Y, known for their technological adeptness, are demographic groups that actively engage in online purchasing.\n- The Federal Trade Commission, an organization responsible for regulating online advertising and ensuring the security of consumers' personal information in the United States, oversees electronic commerce firms.\nrelationships:\n- Federal_Trade_Commission REGULATES Electronic_Commerce_Firms\n- E-Commerce ENABLES Online Shopping\n- Consumers PREFERENCE Online Shopping\nentities:\n- Online_Sales_Taxes \n- Organization:Federal_Trade_Commission Regulates online advertising and the security of consumers’ personal information in the U.S.\n- Online_Purchasing \n- Online_Shopping \n- Activity:Online Shopping \n- Concept:E-Commerce \n- Concept:Bargaining_Power_Of_Buyers High because customers can choose among numerous online stores for the lowest price.\n- Electronic_Commerce_Firms \n- Online_Shopping_Experience \n- Group:Consumers \noutside:\n nodes:\n - Organization:Amazon Fastest-growing, multinational e-commerce retailer in America with international presence.\n - Location:China_And_India Emerging countries with large populations and growing disposable income.\n - Group:Baby Boomers \n - Concept:3D_Virtual_Technology Technology that will take online shopping to new heights.\n - Concept:Modern Tech Support \n - Concept:Web Security \n - Concept:Electronic_Devices Devices such as smartphones that deliver easy and convenient transaction processes.\n - Technology:3D Virtual Technology \n - Technology:Online Payment Methods \n - Demographic_group:Generation_X_And_Y Technologically adept generations that engage more in online purchasing.\n relationships:\n - Organization:Amazon DISCLOSES Online_Sales_Taxes\n - Organization:Amazon BENEFIT Activity:Online Shopping\n - Location:China_And_India OPPORTUNITY_FOR Online_Shopping\n - Group:Baby Boomers LESS_INVOLVED Activity:Online Shopping\n - Concept:3D_Virtual_Technology ENHANCES Online_Shopping\n - Concept:Modern Tech Support FACILITATES Activity:Online Shopping\n - Concept:Web Security FACILITATES Activity:Online Shopping\n - Concept:Electronic_Devices FACILITATES Online_Shopping\n - Technology:3D Virtual Technology FUTURE Activity:Online Shopping\n - Technology:Online Payment Methods ENHANCES Activity:Online Shopping\n - Demographic_group:Generation_X_And_Y ENGAGES_IN Online_Purchasing\n\nDocument end\n""]","Online retailers like Amazon should be careful about disclosing online sales taxes in their advertisements because different sales taxes can cause confusion to customers, especially in the context of cross-border transactions.",simple,0.9999999999,1.0,0.3333333333333333,0.9999999999999997,0.5748866568875494 +Why should online retailers like Amazon be careful about disclosing online sales taxes in their advertisements?,graph+vector,"Online retailers like Amazon should be cautious about disclosing online sales taxes in their advertisements to avoid causing confusion to customers. Different sales tax regulations in various regions can lead to discrepancies and misunderstandings among customers. By being transparent about online sales taxes, retailers can maintain trust and clarity in their transactions, ensuring a positive customer experience and compliance with legal requirements.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: Text Content:\n Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers. Demographic As the world’s population is aging rapidly, baby boomers are moving towards retirement so that they will have weaker purchasing power. Thus, generation X and Y have become companies’ target markets for product selling. These generations are technologically adept and tend to engage more in online purchasing. Based on a survey, 62 percent of Generation Y liked to purchase things online, as compared to 32 percent of those aged older than 50. Organizations \n----\n tanked, many people chose to migrate their shopping onto an online platform. In 2011, online sales actually increased by 11 percent despite what people imagined. The reason this has \n----\n\t\r \xa0 3 online payment methods such as online banking and PayPal create more convenience in purchase transactions, which in turn enhances customers’ online shopping experience. Also, the invention of electronic devices such as smartphones deliver easy and convenient transaction processes, further facilitating online shopping. For instance, Amazon recently released a smartphone app for their Kindle services, allowing users to conveniently access the online sales platform and review products before purchasing. In the future, the use of 3D virtual technology to market products will also take online shopping to new heights. Political/Legal In the modern day environment, firms must be cautious when they deal with international policies on online distribution. In the U.S., electronic commerce firms are regulated by the Federal Trade Commission, which regulates online advertising and the security of consumers’ personal information. On the other hand, International Consumer Protection and Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\nEntities:\n:Cost Leadership\n:Cross-Border_Transactions\n:Differentiation\n:Electronic_Commerce_Firms\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Online_Shopping\n:Smartphone_App\nActivity:Online Shopping\nConcept:Bargaining_Power_Of_Buyers (High because customers can choose among numerous online stores for the lowest price.)\nConcept:E-Commerce\nConcept:Electronic_Devices (Devices such as smartphones that deliver easy and convenient transaction processes.)\nConcept:Web Security\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nGroup:Baby Boomers\nGroup:Consumers\nGroup:Generation X\nGroup:Generation Y\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nMarket:Emerging Markets\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Federal_Trade_Commission (Regulates online advertising and the security of consumers’ personal information in the U.S.)\nOrganization:Icpen (Finds ways to tackle consumer problems involving cross-border transactions.)\nOrganization:International Consumer Protection And Enforcement Network\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:3D Virtual Technology\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\nTechnology:Internet\nTechnology:Online Payment Methods\nTechnology:Smartphones\n----\nRelationships:\nConcept:E-Commerce ENABLES Activity:Online Shopping\nConcept:Electronic_Devices FACILITATES :Online_Shopping\nConcept:Web Security FACILITATES Activity:Online Shopping\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nGroup:Baby Boomers LESS_INVOLVED Activity:Online Shopping\nGroup:Consumers PREFERENCE Activity:Online Shopping\nGroup:Generation X TARGET_MARKET Activity:Online Shopping\nGroup:Generation Y TARGET_MARKET Activity:Online Shopping\nMarket:Emerging Markets GROWTH Activity:Online Shopping\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Federal_Trade_Commission REGULATES :Electronic_Commerce_Firms\nOrganization:Icpen ADDRESSES :Cross-Border_Transactions\nOrganization:International Consumer Protection And Enforcement Network SUPPORTS Organization:Amazon\nOrganization:Wal-Mart USES :Cost Leadership\nTechnology:3D Virtual Technology FUTURE Activity:Online Shopping\nTechnology:Internet SUPPORTS Activity:Online Shopping\nTechnology:Online Payment Methods ENHANCES Activity:Online Shopping\nTechnology:Smartphones FACILITATES Activity:Online Shopping\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: Text Content:\n Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers. Demographic As the world’s population is aging rapidly, baby boomers are moving towards retirement so that they will have weaker purchasing power. Thus, generation X and Y have become companies’ target markets for product selling. These generations are technologically adept and tend to engage more in online purchasing. Based on a survey, 62 percent of Generation Y liked to purchase things online, as compared to 32 percent of those aged older than 50. Organizations \n----\n tanked, many people chose to migrate their shopping onto an online platform. In 2011, online sales actually increased by 11 percent despite what people imagined. The reason this has \n----\n\t\r \xa0 3 online payment methods such as online banking and PayPal create more convenience in purchase transactions, which in turn enhances customers’ online shopping experience. Also, the invention of electronic devices such as smartphones deliver easy and convenient transaction processes, further facilitating online shopping. For instance, Amazon recently released a smartphone app for their Kindle services, allowing users to conveniently access the online sales platform and review products before purchasing. In the future, the use of 3D virtual technology to market products will also take online shopping to new heights. Political/Legal In the modern day environment, firms must be cautious when they deal with international policies on online distribution. In the U.S., electronic commerce firms are regulated by the Federal Trade Commission, which regulates online advertising and the security of consumers’ personal information. On the other hand, International Consumer Protection and Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\nEntities:\n:Cost Leadership\n:Cross-Border_Transactions\n:Differentiation\n:Electronic_Commerce_Firms\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Online_Shopping\n:Smartphone_App\nActivity:Online Shopping\nConcept:Bargaining_Power_Of_Buyers (High because customers can choose among numerous online stores for the lowest price.)\nConcept:E-Commerce\nConcept:Electronic_Devices (Devices such as smartphones that deliver easy and convenient transaction processes.)\nConcept:Web Security\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nGroup:Baby Boomers\nGroup:Consumers\nGroup:Generation X\nGroup:Generation Y\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nMarket:Emerging Markets\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Federal_Trade_Commission (Regulates online advertising and the security of consumers’ personal information in the U.S.)\nOrganization:Icpen (Finds ways to tackle consumer problems involving cross-border transactions.)\nOrganization:International Consumer Protection And Enforcement Network\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:3D Virtual Technology\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\nTechnology:Internet\nTechnology:Online Payment Methods\nTechnology:Smartphones\n----\nRelationships:\nConcept:E-Commerce ENABLES Activity:Online Shopping\nConcept:Electronic_Devices FACILITATES :Online_Shopping\nConcept:Web Security FACILITATES Activity:Online Shopping\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nGroup:Baby Boomers LESS_INVOLVED Activity:Online Shopping\nGroup:Consumers PREFERENCE Activity:Online Shopping\nGroup:Generation X TARGET_MARKET Activity:Online Shopping\nGroup:Generation Y TARGET_MARKET Activity:Online Shopping\nMarket:Emerging Markets GROWTH Activity:Online Shopping\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Federal_Trade_Commission REGULATES :Electronic_Commerce_Firms\nOrganization:Icpen ADDRESSES :Cross-Border_Transactions\nOrganization:International Consumer Protection And Enforcement Network SUPPORTS Organization:Amazon\nOrganization:Wal-Mart USES :Cost Leadership\nTechnology:3D Virtual Technology FUTURE Activity:Online Shopping\nTechnology:Internet SUPPORTS Activity:Online Shopping\nTechnology:Online Payment Methods ENHANCES Activity:Online Shopping\nTechnology:Smartphones FACILITATES Activity:Online Shopping\nDocument end\n']","Online retailers like Amazon should be careful about disclosing online sales taxes in their advertisements because different sales taxes can cause confusion to customers, especially in the context of cross-border transactions.",simple,0.9999999999,1.0,0.5555555555555556,0.9144513874174006,0.4722205528155351 +Why should online retailers like Amazon be careful about disclosing online sales taxes in their advertisements?,graph+vector+fulltext,"Online retailers like Amazon should be careful about disclosing online sales taxes in their advertisements because different sales tax rates can lead to customer confusion. When advertising products to other countries via online platforms, clear disclosure of online sales taxes is crucial to avoid customer misunderstandings and ensure transparency in pricing. Failure to disclose these taxes can result in customer dissatisfaction and potential legal issues related to misleading advertising practices.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: Text Content:\n Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers. Demographic As the world’s population is aging rapidly, baby boomers are moving towards retirement so that they will have weaker purchasing power. Thus, generation X and Y have become companies’ target markets for product selling. These generations are technologically adept and tend to engage more in online purchasing. Based on a survey, 62 percent of Generation Y liked to purchase things online, as compared to 32 percent of those aged older than 50. Organizations \n----\n\t\r \xa0 3 online payment methods such as online banking and PayPal create more convenience in purchase transactions, which in turn enhances customers’ online shopping experience. Also, the invention of electronic devices such as smartphones deliver easy and convenient transaction processes, further facilitating online shopping. For instance, Amazon recently released a smartphone app for their Kindle services, allowing users to conveniently access the online sales platform and review products before purchasing. In the future, the use of 3D virtual technology to market products will also take online shopping to new heights. Political/Legal In the modern day environment, firms must be cautious when they deal with international policies on online distribution. In the U.S., electronic commerce firms are regulated by the Federal Trade Commission, which regulates online advertising and the security of consumers’ personal information. On the other hand, International Consumer Protection and Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions \n----\n tanked, many people chose to migrate their shopping onto an online platform. In 2011, online sales actually increased by 11 percent despite what people imagined. The reason this has \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Sales_Taxes\n:Smartphone_App\nActivity:Online Shopping\nConcept:E-Commerce\nConcept:Modern Tech Support\nConcept:Web Security\nGroup:Baby Boomers\nGroup:Consumers\nGroup:Generation X\nGroup:Generation Y\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nMarket:Emerging Markets\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Federal Trade Commission\nOrganization:International Consumer Protection And Enforcement Network\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:3D Virtual Technology\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\nTechnology:Internet\nTechnology:Online Payment Methods\nTechnology:Smartphones\n----\nRelationships:\nConcept:E-Commerce ENABLES Activity:Online Shopping\nConcept:Modern Tech Support FACILITATES Activity:Online Shopping\nConcept:Web Security FACILITATES Activity:Online Shopping\nGroup:Baby Boomers LESS_INVOLVED Activity:Online Shopping\nGroup:Consumers PREFERENCE Activity:Online Shopping\nGroup:Generation X TARGET_MARKET Activity:Online Shopping\nGroup:Generation Y TARGET_MARKET Activity:Online Shopping\nMarket:Emerging Markets GROWTH Activity:Online Shopping\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Federal Trade Commission REGULATES Organization:Amazon\nOrganization:International Consumer Protection And Enforcement Network SUPPORTS Organization:Amazon\nOrganization:Wal-Mart USES :Cost Leadership\nTechnology:3D Virtual Technology FUTURE Activity:Online Shopping\nTechnology:Internet SUPPORTS Activity:Online Shopping\nTechnology:Online Payment Methods ENHANCES Activity:Online Shopping\nTechnology:Smartphones FACILITATES Activity:Online Shopping\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: Text Content:\n Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers. Demographic As the world’s population is aging rapidly, baby boomers are moving towards retirement so that they will have weaker purchasing power. Thus, generation X and Y have become companies’ target markets for product selling. These generations are technologically adept and tend to engage more in online purchasing. Based on a survey, 62 percent of Generation Y liked to purchase things online, as compared to 32 percent of those aged older than 50. Organizations \n----\n\t\r \xa0 3 online payment methods such as online banking and PayPal create more convenience in purchase transactions, which in turn enhances customers’ online shopping experience. Also, the invention of electronic devices such as smartphones deliver easy and convenient transaction processes, further facilitating online shopping. For instance, Amazon recently released a smartphone app for their Kindle services, allowing users to conveniently access the online sales platform and review products before purchasing. In the future, the use of 3D virtual technology to market products will also take online shopping to new heights. Political/Legal In the modern day environment, firms must be cautious when they deal with international policies on online distribution. In the U.S., electronic commerce firms are regulated by the Federal Trade Commission, which regulates online advertising and the security of consumers’ personal information. On the other hand, International Consumer Protection and Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions \n----\n tanked, many people chose to migrate their shopping onto an online platform. In 2011, online sales actually increased by 11 percent despite what people imagined. The reason this has \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Sales_Taxes\n:Smartphone_App\nActivity:Online Shopping\nConcept:E-Commerce\nConcept:Modern Tech Support\nConcept:Web Security\nGroup:Baby Boomers\nGroup:Consumers\nGroup:Generation X\nGroup:Generation Y\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nMarket:Emerging Markets\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Federal Trade Commission\nOrganization:International Consumer Protection And Enforcement Network\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:3D Virtual Technology\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\nTechnology:Internet\nTechnology:Online Payment Methods\nTechnology:Smartphones\n----\nRelationships:\nConcept:E-Commerce ENABLES Activity:Online Shopping\nConcept:Modern Tech Support FACILITATES Activity:Online Shopping\nConcept:Web Security FACILITATES Activity:Online Shopping\nGroup:Baby Boomers LESS_INVOLVED Activity:Online Shopping\nGroup:Consumers PREFERENCE Activity:Online Shopping\nGroup:Generation X TARGET_MARKET Activity:Online Shopping\nGroup:Generation Y TARGET_MARKET Activity:Online Shopping\nMarket:Emerging Markets GROWTH Activity:Online Shopping\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Federal Trade Commission REGULATES Organization:Amazon\nOrganization:International Consumer Protection And Enforcement Network SUPPORTS Organization:Amazon\nOrganization:Wal-Mart USES :Cost Leadership\nTechnology:3D Virtual Technology FUTURE Activity:Online Shopping\nTechnology:Internet SUPPORTS Activity:Online Shopping\nTechnology:Online Payment Methods ENHANCES Activity:Online Shopping\nTechnology:Smartphones FACILITATES Activity:Online Shopping\nDocument end\n\n\nDocument start\nThis Document belongs to the source Alphabet_Q1_stock.pdf\nContent: Text Content:\n Alphabet reports revenue and earnings beat for first quarter PUBLISHED TUE, APR 25 20239:00 AM EDTUPDATED TUE, APR 25 20239:25 PM EDT Alphabet reported first-quarter results on Tuesday that exceeded analysts estimates. The stock jumped over 4% in extended trading before paring its gains. The company also said its board authorized a $70 billion share buyback. Here are the key numbers: • Earnings: $1.17 per share vs. $1.07 per share expected, according to Refinitiv. • Revenue: $69.79 billion vs. $68.9 billion expected, according to Refinitiv. The beat on the top and bottom lines breaks a string of four straight quarters in which the company missed consensus estimates. • YouTube advertising revenue: $6.69 billion vs. $6.6 billion, according to StreetAccount. \n----\nOn its investor call, finance chief Ruth Porat said due to the challenging economic environment the outlook remains uncertain. Ad revenue beat analyst expectations, but fell from the year prior to $54.55 billion. YouTube ad revenue stayed in line with analyst expectations, also declining from a year ago. In addition to the overall pullback in ad spending, YouTube is also facing heightened competition from TikTok in short-form videos. To grapple with the recent advertising weakness, Google has had to make its most extreme cuts in company history, including laying off 12,000 employees — about 6% of its workforce — in January. This month, CFO Ruth Porat announced “multi-year” cuts to things like real estate, employee services and equipment. Alphabet reported $2.6 billion in charges related to the layoffs and office space reduction during the quarter. Net income fell to $15.05 billion, or $1.\n----\nEntities:\nOrganization:Alphabet\nOrganization:Deepmind\nOrganization:Google\nOrganization:Google Cloud\nOrganization:Verily\nOrganization:Waymo\nOrganization:Youtube\nPerson:Ruth Porat\n----\nRelationships:\nOrganization:Alphabet CFO Person:Ruth Porat\nOrganization:Alphabet SUBSIDIARY Organization:Google Cloud\nOrganization:Alphabet SUBSIDIARY Organization:Verily\nOrganization:Alphabet SUBSIDIARY Organization:Waymo\nOrganization:Alphabet SUBSIDIARY Organization:Youtube\nOrganization:Deepmind SUBSIDIARY Organization:Alphabet\nOrganization:Google SUBSIDIARY Organization:Alphabet\nOrganization:Verily SUBSIDIARY Organization:Alphabet\nOrganization:Waymo SUBSIDIARY Organization:Alphabet\nDocument end\n']","Online retailers like Amazon should be careful about disclosing online sales taxes in their advertisements because different sales taxes can cause confusion to customers, especially in the context of cross-border transactions.",simple,0.9999999999,1.0,0.5714285714285714,0.999998130852297,0.934309972514247 +Why should online retailers like Amazon be careful about disclosing online sales taxes in their advertisements?,global search+vector+fulltext,"Online retailers like Amazon should be cautious about disclosing online sales taxes in their advertisements to maintain transparency and compliance with regulations. By clearly stating the inclusion of sales taxes, they build trust with customers and avoid potential legal issues related to false advertising or misleading practices. Additionally, disclosing online sales taxes helps prevent any misunderstandings or surprises for customers during the checkout process, leading to a smoother shopping experience and reducing the risk of customer dissatisfaction or complaints.","[""Document start\nThis Document belongs to the source unknown\nContent: Amazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offers a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, being regulated by the Federal Trade Commission and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offer a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, regulated by the Federal Trade Commission, and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offers a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, regulated by the Federal Trade Commission, and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nThe Federal Trade Commission, an organization responsible for regulating online advertising and ensuring the security of consumers' personal information in the United States, oversees electronic commerce firms.\n----\nThe Federal Trade Commission (FTC) is a key regulatory body in the United States tasked with overseeing electronic commerce firms. Its primary responsibilities include regulating online advertising practices and ensuring the security and protection of consumers' personal information. The FTC plays a crucial role in maintaining fair and secure digital marketplaces by enforcing laws and guidelines that govern how businesses operate online, thereby safeguarding consumer interests and promoting trust in electronic commerce.\n----\nThe Federal Trade Commission (FTC) is a regulatory body in the United States tasked with overseeing electronic commerce firms. Its primary responsibilities include regulating online advertising practices and ensuring the security and protection of consumers' personal information. The FTC plays a crucial role in maintaining fair and secure digital marketplaces by enforcing laws and guidelines that govern how businesses operate online, thereby safeguarding consumer interests.\n----\nThe Federal Trade Commission (FTC) is a key regulatory body in the United States tasked with overseeing electronic commerce firms. Its primary responsibilities include regulating online advertising practices and ensuring the security and protection of consumers' personal information. The FTC plays a crucial role in maintaining fair and secure digital marketplaces, safeguarding consumer rights, and promoting trust in online transactions.\n----\nAmazon is a rapidly growing multinational e-commerce retailer based in America with a significant international presence. It faces competition from major organizations such as eBay, Barnes and Noble, and Wal-Mart. eBay and Barnes and Noble are noted for their product breadth and geographic market coverage, while Wal-Mart is recognized as the world's largest retail chain, employing a cost leadership strategy.\n\nAmazon competes with eBay, which utilizes both cost leadership and differentiation strategies. Barnes and Noble also competes with Amazon, employing an integrated focused cost leadership/differentiation strategy. Wal-Mart, another competitor, uses a cost leadership approach.\n\nAmazon is actively investing in various technologies and products, including video content, cloud services, and its Kindle product. It utilizes technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations. The company has also released a smartphone app and is located at the U.S. East Data Center.\n\nAmazon sees opportunities in emerging markets like China, which has a large population and growing disposable income. It is focused on capturing the global market and has invested in distribution centers to support this goal. The company discloses information about online sales taxes and is regulated by the Federal Trade Commission. Additionally, it receives support from the International Consumer Protection and Enforcement Network.\n----\nThe online shopping landscape is undergoing a transformative enhancement through the integration of 3D virtual technology, which aims to significantly elevate the consumer experience. This technological advancement is complemented by the widespread use of electronic devices, particularly smartphones, which are streamlining and simplifying transaction processes for online shoppers. Furthermore, emerging markets, notably China and India, are poised to play a pivotal role in the expansion of online shopping. These countries, characterized by their vast populations and rising disposable incomes, offer substantial opportunities for growth and development in the online retail sector.\n----\nThe online shopping landscape is undergoing a transformative enhancement through the integration of 3D virtual technology, which aims to significantly elevate the consumer experience. This technological advancement is complemented by the widespread use of electronic devices, particularly smartphones, which are streamlining and simplifying transaction processes for online shoppers. Furthermore, emerging markets, notably China and India, are poised to play a pivotal role in the expansion of online shopping. These countries, characterized by their vast populations and rising disposable incomes, offer substantial opportunities for growth and development in the online retail sector.\nDocument end\n""]","Online retailers like Amazon should be careful about disclosing online sales taxes in their advertisements because different sales taxes can cause confusion to customers, especially in the context of cross-border transactions.",simple,0.9999999999,1.0,0.0,0.9788114251760524,0.3457883227733063 +How threatening are substitute products to Amazon's patented tech and customer service?,vector,"Substitute products pose a high threat to Amazon despite its patented technology and customer service. While Amazon's unique features like 1-Click Ordering differentiate it, there are many alternatives offering similar products. This situation diminishes Amazon's competitive advantage in product offerings. However, Amazon maintains an advantage in customer service and convenience, which helps mitigate the threat of substitute products to some extent.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: \t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n\t\r \xa0 3 online payment methods such as online banking and PayPal create more convenience in purchase transactions, which in turn enhances customers’ online shopping experience. Also, the invention of electronic devices such as smartphones deliver easy and convenient transaction processes, further facilitating online shopping. For instance, Amazon recently released a smartphone app for their Kindle services, allowing users to conveniently access the online sales platform and review products before purchasing. In the future, the use of 3D virtual technology to market products will also take online shopping to new heights. Political/Legal In the modern day environment, firms must be cautious when they deal with international policies on online distribution. In the U.S., electronic commerce firms are regulated by the Federal Trade Commission, which regulates online advertising and the security of consumers’ personal information. On the other hand, International Consumer Protection and Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers. Demographic As the world’s population is aging rapidly, baby boomers are moving towards retirement so that they will have weaker purchasing power. Thus, generation X and Y have become companies’ target markets for product selling. These generations are technologically adept and tend to engage more in online purchasing. Based on a survey, 62 percent of Generation Y liked to purchase things online, as compared to 32 percent of those aged older than 50. Organizations \nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: \t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n\t\r \xa0 3 online payment methods such as online banking and PayPal create more convenience in purchase transactions, which in turn enhances customers’ online shopping experience. Also, the invention of electronic devices such as smartphones deliver easy and convenient transaction processes, further facilitating online shopping. For instance, Amazon recently released a smartphone app for their Kindle services, allowing users to conveniently access the online sales platform and review products before purchasing. In the future, the use of 3D virtual technology to market products will also take online shopping to new heights. Political/Legal In the modern day environment, firms must be cautious when they deal with international policies on online distribution. In the U.S., electronic commerce firms are regulated by the Federal Trade Commission, which regulates online advertising and the security of consumers’ personal information. On the other hand, International Consumer Protection and Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers. Demographic As the world’s population is aging rapidly, baby boomers are moving towards retirement so that they will have weaker purchasing power. Thus, generation X and Y have become companies’ target markets for product selling. These generations are technologically adept and tend to engage more in online purchasing. Based on a survey, 62 percent of Generation Y liked to purchase things online, as compared to 32 percent of those aged older than 50. Organizations \nDocument end\n']","The threat of substitutes for Amazon is high. There are many alternatives providing the same products and services, which could reduce Amazon's competitive advantage. However, Amazon does have the advantage when it comes to the quality of customer service and convenience provided.",reasoning,0.9999999999,1.0,0.8333333333333334,0.951196677614003,0.6950129184145829 +How threatening are substitute products to Amazon's patented tech and customer service?,fulltext,"Substitute products pose a high threat to Amazon despite its patented technology and customer service. While Amazon's unique features like 1-Click Ordering differentiate it, there are many alternatives offering similar products. This situation diminishes Amazon's competitive advantage in product offerings. However, Amazon maintains an advantage in customer service and convenience, which helps mitigate the threat of substitutes to some extent.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: \t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n\t\r \xa0 3 online payment methods such as online banking and PayPal create more convenience in purchase transactions, which in turn enhances customers’ online shopping experience. Also, the invention of electronic devices such as smartphones deliver easy and convenient transaction processes, further facilitating online shopping. For instance, Amazon recently released a smartphone app for their Kindle services, allowing users to conveniently access the online sales platform and review products before purchasing. In the future, the use of 3D virtual technology to market products will also take online shopping to new heights. Political/Legal In the modern day environment, firms must be cautious when they deal with international policies on online distribution. In the U.S., electronic commerce firms are regulated by the Federal Trade Commission, which regulates online advertising and the security of consumers’ personal information. On the other hand, International Consumer Protection and Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers. Demographic As the world’s population is aging rapidly, baby boomers are moving towards retirement so that they will have weaker purchasing power. Thus, generation X and Y have become companies’ target markets for product selling. These generations are technologically adept and tend to engage more in online purchasing. Based on a survey, 62 percent of Generation Y liked to purchase things online, as compared to 32 percent of those aged older than 50. Organizations \nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: \t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n\t\r \xa0 3 online payment methods such as online banking and PayPal create more convenience in purchase transactions, which in turn enhances customers’ online shopping experience. Also, the invention of electronic devices such as smartphones deliver easy and convenient transaction processes, further facilitating online shopping. For instance, Amazon recently released a smartphone app for their Kindle services, allowing users to conveniently access the online sales platform and review products before purchasing. In the future, the use of 3D virtual technology to market products will also take online shopping to new heights. Political/Legal In the modern day environment, firms must be cautious when they deal with international policies on online distribution. In the U.S., electronic commerce firms are regulated by the Federal Trade Commission, which regulates online advertising and the security of consumers’ personal information. On the other hand, International Consumer Protection and Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers. Demographic As the world’s population is aging rapidly, baby boomers are moving towards retirement so that they will have weaker purchasing power. Thus, generation X and Y have become companies’ target markets for product selling. These generations are technologically adept and tend to engage more in online purchasing. Based on a survey, 62 percent of Generation Y liked to purchase things online, as compared to 32 percent of those aged older than 50. Organizations \nDocument end\n']","The threat of substitutes for Amazon is high. There are many alternatives providing the same products and services, which could reduce Amazon's competitive advantage. However, Amazon does have the advantage when it comes to the quality of customer service and convenience provided.",reasoning,0.9999999999,1.0,1.0,0.9511736417752749,0.6802307199189462 +How threatening are substitute products to Amazon's patented tech and customer service?,entity search+vector,"Substitute products can pose a moderate threat to Amazon's patented technology and customer service. While Amazon has established a strong presence and loyal customer base, competitors offering similar products or services could potentially lure customers away. Amazon's patented technology and exceptional customer service are key differentiators that help mitigate this threat, but continuous innovation and customer-centric strategies are essential to maintain a competitive edge in the market.","[""Document start\nThis Document belongs to the source unknown\nContent: chunks:\n- providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n- \t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n- since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \ncommunities:\n- Neo4j is a comprehensive graph database management system that offers a wide range of products, services, and resources to support graph data science and related applications. It provides various deployment options, including Cloud Managed Services, Self-Hosted, and Graph-As-A-Service, with Amazon AWS as a cloud provider. Neo4j's offerings include the Neo4j Graph Data Science product, Neo4j GraphQL Library, Neo4j Workspace, Neo4j Bloom visualization tool, Neo4j Developer Tools, and Neo4j Data Connectors, all of which are integral parts of the Neo4j ecosystem.\n\nThe organization supports learning and development through resources like Graphacademy, which offers free online courses and certifications, and the Neo4j Blog for daily insights. It also provides a Resource Library with white papers and data sheets, Case Studies showcasing customer success stories, and Executive Insights on graph technology.\n\nNeo4j hosts various events, including the Neo4j Events Hub for live and on-demand training, webinars, and demos, the quarterly online conference Connections, and the global Graphsummit tour. The Cypher query language is a key technology used within Neo4j for exploring and manipulating graph data.\n\nAdditionally, Neo4j includes a company structure with information about its culture, diversity, leadership, and partnerships, offering opportunities to find or become a partner through its Partner Portal.\n- Prabhakar Raghavan is an employee at Google, where Sundar Pichai serves as the CEO. Google has developed several products, including Bard, Pixel, and Android. The company has established partnerships with major organizations such as Samsung and Apple. Additionally, Samsung is considering changes in its relationship with Google.\n- Amazon.com, founded in 1993 by Jeff Benzos, initially started as an online bookstore. Over the years, it has grown into a massive retail enterprise valued at $48 billion, offering products across more than forty categories. The company experienced significant growth momentum during the Dot-Com Bubble. Jeff Benzos, the founder, played a pivotal role in its development and expansion.\nrelationships:\n- Amazon COMPETITOR Wal-Mart\n- Amazon COMPETES_WITH Wal-Mart\n- Federal_Trade_Commission REGULATES Electronic_Commerce_Firms\nentities:\n- Organization:Amazon Fastest-growing, multinational e-commerce retailer in America with international presence.\n- Organization:Amazon Cooperation Treaty Organization \n- Company:Amazon Aws \n- Electronic_Commerce_Firms \n- Company:Amazon.Com Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.\n- Group:Consumers \n- Organization:Apple \n- Organization:Federal_Trade_Commission Regulates online advertising and the security of consumers’ personal information in the U.S.\n- Organization:Wal-Mart World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.\n- Online_Shopping \noutside:\n nodes:\n - Organization:Ebay Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.\n - Organization:Barnes And Noble Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.\n - Activity:Online Shopping \n - Organization:Federal Trade Commission \n - Technology:Elastic Block Storage (Ebs) \n - Country:China Emerging country with large population and growing disposable income.\n - Technology:Cloud \n - Product:Video Content \n - Country:India Emerging country with large population and growing disposable income.\n - Organization:International Consumer Protection And Enforcement Network \n relationships:\n - Organization:Amazon COMPETITOR Organization:Ebay\n - Organization:Ebay COMPETES_WITH Organization:Amazon\n - Organization:Amazon COMPETES_WITH Organization:Ebay\n - Organization:Amazon COMPETITOR Organization:Barnes And Noble\n - Organization:Barnes And Noble COMPETES_WITH Organization:Amazon\n - Organization:Amazon COMPETES_WITH Organization:Barnes And Noble\n - Organization:Amazon BENEFIT Activity:Online Shopping\n - Group:Consumers PREFERENCE Activity:Online Shopping\n - Organization:Federal Trade Commission REGULATES Organization:Amazon\n - Organization:Amazon USES Technology:Elastic Block Storage (Ebs)\n - Organization:Amazon OPPORTUNITY Country:China\n - Organization:Amazon INVESTS_IN Technology:Cloud\n - Organization:Amazon INVESTS_IN Product:Video Content\n - Organization:Amazon OPPORTUNITY Country:India\n - Organization:International Consumer Protection And Enforcement Network SUPPORTS Organization:Amazon\n\nDocument end\n""]","The threat of substitutes for Amazon is high. There are many alternatives providing the same products and services, which could reduce Amazon's competitive advantage. However, Amazon does have the advantage when it comes to the quality of customer service and convenience provided.",reasoning,0.9999999999,0.0,0.5555555555555556,0.9668322495233318,0.5657109211952066 +How threatening are substitute products to Amazon's patented tech and customer service?,graph+vector,"Substitute products pose a high threat to Amazon despite its patented technology like 1-Click Ordering. While these unique features differentiate Amazon, there are many alternatives offering similar products. However, Amazon's competitive advantage lies in its quality customer service and convenience rather than absolute product uniqueness.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: Text Content:\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n\t\r \xa0 3 online payment methods such as online banking and PayPal create more convenience in purchase transactions, which in turn enhances customers’ online shopping experience. Also, the invention of electronic devices such as smartphones deliver easy and convenient transaction processes, further facilitating online shopping. For instance, Amazon recently released a smartphone app for their Kindle services, allowing users to conveniently access the online sales platform and review products before purchasing. In the future, the use of 3D virtual technology to market products will also take online shopping to new heights. Political/Legal In the modern day environment, firms must be cautious when they deal with international policies on online distribution. In the U.S., electronic commerce firms are regulated by the Federal Trade Commission, which regulates online advertising and the security of consumers’ personal information. On the other hand, International Consumer Protection and Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers. Demographic As the world’s population is aging rapidly, baby boomers are moving towards retirement so that they will have weaker purchasing power. Thus, generation X and Y have become companies’ target markets for product selling. These generations are technologically adept and tend to engage more in online purchasing. Based on a survey, 62 percent of Generation Y liked to purchase things online, as compared to 32 percent of those aged older than 50. Organizations \n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Sales_Taxes\n:Smartphone_App\nActivity:Online Shopping\nConcept:E-Commerce\nConcept:Modern Tech Support\nConcept:Web Security\nGroup:Baby Boomers\nGroup:Consumers\nGroup:Generation X\nGroup:Generation Y\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nMarket:Emerging Markets\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Federal Trade Commission\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:3D Virtual Technology\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\nTechnology:Internet\nTechnology:Online Payment Methods\nTechnology:Smartphones\n----\nRelationships:\nConcept:E-Commerce ENABLES Activity:Online Shopping\nConcept:Modern Tech Support FACILITATES Activity:Online Shopping\nConcept:Web Security FACILITATES Activity:Online Shopping\nGroup:Baby Boomers LESS_INVOLVED Activity:Online Shopping\nGroup:Consumers PREFERENCE Activity:Online Shopping\nGroup:Generation X TARGET_MARKET Activity:Online Shopping\nGroup:Generation Y TARGET_MARKET Activity:Online Shopping\nMarket:Emerging Markets GROWTH Activity:Online Shopping\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Federal Trade Commission REGULATES Organization:Amazon\nOrganization:Wal-Mart USES :Cost Leadership\nTechnology:3D Virtual Technology FUTURE Activity:Online Shopping\nTechnology:Internet SUPPORTS Activity:Online Shopping\nTechnology:Online Payment Methods ENHANCES Activity:Online Shopping\nTechnology:Smartphones FACILITATES Activity:Online Shopping\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: Text Content:\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n\t\r \xa0 3 online payment methods such as online banking and PayPal create more convenience in purchase transactions, which in turn enhances customers’ online shopping experience. Also, the invention of electronic devices such as smartphones deliver easy and convenient transaction processes, further facilitating online shopping. For instance, Amazon recently released a smartphone app for their Kindle services, allowing users to conveniently access the online sales platform and review products before purchasing. In the future, the use of 3D virtual technology to market products will also take online shopping to new heights. Political/Legal In the modern day environment, firms must be cautious when they deal with international policies on online distribution. In the U.S., electronic commerce firms are regulated by the Federal Trade Commission, which regulates online advertising and the security of consumers’ personal information. On the other hand, International Consumer Protection and Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers. Demographic As the world’s population is aging rapidly, baby boomers are moving towards retirement so that they will have weaker purchasing power. Thus, generation X and Y have become companies’ target markets for product selling. These generations are technologically adept and tend to engage more in online purchasing. Based on a survey, 62 percent of Generation Y liked to purchase things online, as compared to 32 percent of those aged older than 50. Organizations \n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Sales_Taxes\n:Smartphone_App\nActivity:Online Shopping\nConcept:E-Commerce\nConcept:Modern Tech Support\nConcept:Web Security\nGroup:Baby Boomers\nGroup:Consumers\nGroup:Generation X\nGroup:Generation Y\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nMarket:Emerging Markets\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Federal Trade Commission\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:3D Virtual Technology\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\nTechnology:Internet\nTechnology:Online Payment Methods\nTechnology:Smartphones\n----\nRelationships:\nConcept:E-Commerce ENABLES Activity:Online Shopping\nConcept:Modern Tech Support FACILITATES Activity:Online Shopping\nConcept:Web Security FACILITATES Activity:Online Shopping\nGroup:Baby Boomers LESS_INVOLVED Activity:Online Shopping\nGroup:Consumers PREFERENCE Activity:Online Shopping\nGroup:Generation X TARGET_MARKET Activity:Online Shopping\nGroup:Generation Y TARGET_MARKET Activity:Online Shopping\nMarket:Emerging Markets GROWTH Activity:Online Shopping\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Federal Trade Commission REGULATES Organization:Amazon\nOrganization:Wal-Mart USES :Cost Leadership\nTechnology:3D Virtual Technology FUTURE Activity:Online Shopping\nTechnology:Internet SUPPORTS Activity:Online Shopping\nTechnology:Online Payment Methods ENHANCES Activity:Online Shopping\nTechnology:Smartphones FACILITATES Activity:Online Shopping\nDocument end\n']","The threat of substitutes for Amazon is high. There are many alternatives providing the same products and services, which could reduce Amazon's competitive advantage. However, Amazon does have the advantage when it comes to the quality of customer service and convenience provided.",reasoning,0.9999999999,1.0,1.0,0.0,0.7728515969055618 +How threatening are substitute products to Amazon's patented tech and customer service?,graph+vector+fulltext,"Substitute products pose a high threat to Amazon despite its patented technology like 1-Click Ordering. While these technologies differentiate Amazon, there are many alternatives offering similar products. However, Amazon's competitive advantage lies in its quality customer service and convenience rather than absolute product uniqueness.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: Text Content:\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Sales_Taxes\n:Smartphone_App\nActivity:Online Shopping\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nMarket:Emerging Markets\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nMarket:Emerging Markets GROWTH Activity:Online Shopping\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Shivam D\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: Text Content:\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Sales_Taxes\n:Smartphone_App\nActivity:Online Shopping\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nMarket:Emerging Markets\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nMarket:Emerging Markets GROWTH Activity:Online Shopping\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Shivam D\nDocument end\n']","The threat of substitutes for Amazon is high. There are many alternatives providing the same products and services, which could reduce Amazon's competitive advantage. However, Amazon does have the advantage when it comes to the quality of customer service and convenience provided.",reasoning,0.9999999999,1.0,1.0,0.8926176723855943,0.8618653144968493 +How threatening are substitute products to Amazon's patented tech and customer service?,global search+vector+fulltext,"Substitute products can pose a moderate threat to Amazon's patented technology and customer service. While Amazon's patents provide a level of protection for its innovations, substitute products could still impact its market share and competitive position. Amazon's strong customer service reputation may mitigate some of this threat by fostering customer loyalty. However, continuous innovation and strategic differentiation are crucial for Amazon to stay ahead of potential substitutes in the rapidly evolving e-commerce landscape.","[""Document start\nThis Document belongs to the source unknown\nContent: Amazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offers a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, being regulated by the Federal Trade Commission and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nNeo4j is a comprehensive graph database management system that offers a wide range of products, services, and resources to support graph data science and related applications. It provides various deployment options, including Cloud Managed Services, Self-Hosted, and Graph-As-A-Service, with Amazon AWS as a cloud provider. Neo4j's offerings include the Neo4j Graph Data Science product, Neo4j GraphQL Library, Neo4j Workspace, Neo4j Bloom visualization tool, Neo4j Developer Tools, and Neo4j Data Connectors, all of which are integral parts of the Neo4j ecosystem.\n\nThe organization supports learning and development through resources like Graphacademy, which offers free online courses and certifications, and the Neo4j Blog for daily insights. It also provides a Resource Library with white papers and data sheets, Case Studies showcasing customer success stories, and Executive Insights on graph technology.\n\nNeo4j hosts various events, including the Neo4j Events Hub for live and on-demand training, webinars, and demos, the quarterly online conference Connections, and the global Graphsummit tour. The Cypher query language is a key technology used within Neo4j for exploring and manipulating graph data.\n\nAdditionally, Neo4j includes a company structure with information about its culture, diversity, leadership, and partnerships, offering opportunities to find or become a partner through its Partner Portal.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offer a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, regulated by the Federal Trade Commission, and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offers a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, regulated by the Federal Trade Commission, and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nAmazon is a rapidly growing multinational e-commerce retailer based in America with a significant international presence. It faces competition from major organizations such as eBay, Barnes and Noble, and Wal-Mart. eBay and Barnes and Noble are noted for their product breadth and geographic market coverage, while Wal-Mart is recognized as the world's largest retail chain, employing a cost leadership strategy.\n\nAmazon competes with eBay, which utilizes both cost leadership and differentiation strategies. Barnes and Noble also competes with Amazon, employing an integrated focused cost leadership/differentiation strategy. Wal-Mart, another competitor, uses a cost leadership approach.\n\nAmazon is actively investing in various technologies and products, including video content, cloud services, and its Kindle product. It utilizes technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations. The company has also released a smartphone app and is located at the U.S. East Data Center.\n\nAmazon sees opportunities in emerging markets like China, which has a large population and growing disposable income. It is focused on capturing the global market and has invested in distribution centers to support this goal. The company discloses information about online sales taxes and is regulated by the Federal Trade Commission. Additionally, it receives support from the International Consumer Protection and Enforcement Network.\n----\nThe community consists of a group of individuals, Jin Can Chen, Jae Kim, Jessica Zhang, John Chen, and Tristan Landrecht, who are enrolled in Bus 478, a seminar focused on business strategy. This course involves a collaborative or team-based approach, suggesting that these members work closely together on projects or discussions related to business strategy. Additionally, the community is linked to Amazon.com, a company founded in 1993 by Jeff Benzos. Originally an online bookstore, Amazon has evolved into a vast retail enterprise valued at $48 billion, offering a wide range of products across more than forty categories. The company saw substantial growth during the Dot-Com Bubble, with Jeff Benzos playing a crucial role in its expansion and success. This connection to Amazon may indicate that the course or group discussions could involve case studies or strategic analyses of Amazon's business model and growth trajectory.\n----\nAmazon.com, founded in 1993 by Jeff Benzos, initially started as an online bookstore. Over the years, it has grown into a massive retail enterprise valued at $48 billion, offering products across more than forty categories. The company experienced significant growth momentum during the Dot-Com Bubble. Jeff Benzos, the founder, played a pivotal role in its development and expansion.\n----\nThe summaries collectively highlight a network of prominent technology companies and their products, partnerships, and organizational structures. Google, led by CEO Sundar Pichai, is a key player with products like Bard, Pixel, and Android, and partnerships with major companies such as Samsung and Apple. Samsung is contemplating changes in its relationship with Google. Alphabet, Google's parent company, encompasses a diverse range of subsidiaries, including Verily, Waymo, Google Cloud, YouTube, and DeepMind, with Ruth Porat as CFO. This structure underscores Alphabet's broad interests in technology, healthcare, and media.\n\nMicrosoft, another major organization, has developed Bing and faces competition from Gemini Ai. OpenAI is noted for its product, ChatGPT. Neo4j is a comprehensive graph database management system offering a suite of products and services, including Neo4j Graph Data Science, Neo4j GraphQL Library, and Neo4j Bloom, among others. It supports learning through Graphacademy and hosts events like the Neo4j Events Hub and Graphsummit. Neo4j Auradb, a cloud-based service, provides advanced graph database and analytics capabilities with enterprise-grade security.\n\nOverall, these summaries depict a vibrant ecosystem of technology companies, each contributing to advancements in their respective fields through innovative products, strategic partnerships, and a commitment to development and learning.\n----\nThe summaries collectively highlight a network of prominent technology companies and their products, partnerships, and organizational structures. Google, led by CEO Sundar Pichai, is a key player with products like Bard, Pixel, and Android, and partnerships with major companies such as Samsung and Apple. Samsung is contemplating changes in its relationship with Google. Alphabet, Google's parent company, encompasses a diverse range of subsidiaries, including Verily, Waymo, Google Cloud, YouTube, and DeepMind, with Ruth Porat as CFO. This structure underscores Alphabet's broad interests in technology, healthcare, and media.\n\nMicrosoft, another major organization, has developed Bing and faces competition from Gemini Ai. OpenAI is noted for its product, ChatGPT. Neo4j is a comprehensive graph database management system offering a suite of products and services, including Neo4j Graph Data Science, Neo4j GraphQL Library, and Neo4j Bloom, among others. It supports learning through Graphacademy and hosts events like the Neo4j Events Hub and Graphsummit. Neo4j Auradb, a cloud-based service, provides advanced graph database and analytics capabilities with enterprise-grade security.\n\nOverall, these summaries depict a vibrant ecosystem of technology companies, each contributing to advancements in their respective fields through innovative products, strategic partnerships, and a commitment to development and education.\n----\nThe community consists of individuals and entities connected through educational and business endeavors. Jin Can Chen, Jae Kim, Jessica Zhang, John Chen, and Tristan Landrecht are all participants in Bus 478, a seminar focused on business strategy, which emphasizes teamwork and collaboration. This educational setting likely fosters skills relevant to business growth and strategy, akin to those demonstrated by Amazon.com. Founded in 1993 by Jeff Benzos, Amazon began as an online bookstore and evolved into a vast retail empire valued at $48 billion, offering a diverse range of products across more than forty categories. The company's significant expansion, particularly during the Dot-Com Bubble, highlights the importance of strategic business planning and leadership, as exemplified by Benzos' pivotal role in its success. This connection between the educational focus of Bus 478 and the business strategies employed by Amazon underscores the relevance of strategic thinking in both academic and real-world business contexts.\nDocument end\n""]","The threat of substitutes for Amazon is high. There are many alternatives providing the same products and services, which could reduce Amazon's competitive advantage. However, Amazon does have the advantage when it comes to the quality of customer service and convenience provided.",reasoning,0.0,0.0,0.3,0.9667636548197255,0.8461425352478676 +What was the 2012 issue with Amazon's EBS and its proposed fix?,vector,"In 2012, Amazon faced issues with its Elastic Block Storage (EBS) service due to an electric outage at the U.S. East data center in Virginia, the largest and oldest data center causing the outages. To prevent future service disruptions, Amazon planned major upgrades for the U.S. East data center. This upgrade was necessary to avoid inconveniences and discomfort for regular website users caused by server crashes.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\nDocument end\n\n\nDocument start\nThis Document belongs to the source github-recovery-codes.txt\nContent: e6b17-50e48\n----\ne5ab9-b2238\nDocument end\n']","In 2012, Amazon's Elastic Block Storage (EBS) service experienced several outages due to an electric outage. The main problem originated from Amazon's U.S. East data center in Virginia, which is the biggest and oldest data center. The proposed fix for this issue is to perform major upgrades on the U.S. East data center to prevent the services from going down in the future.",reasoning,0.9999999999,1.0,1.0,0.9348951275957792,0.8232985491060043 +What was the 2012 issue with Amazon's EBS and its proposed fix?,fulltext,"In 2012, Amazon faced issues with its Elastic Block Storage (EBS) service due to an electric outage at the U.S. East data center in Virginia. The outage was primarily caused by problems in this data center, which is the largest and oldest, leading to service disruptions. To prevent such incidents in the future and avoid inconvenience to customers, Amazon planned major upgrades for the U.S. East data center.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\nDocument end\n\n\nDocument start\nThis Document belongs to the source github-recovery-codes.txt\nContent: e6b17-50e48\n----\ne5ab9-b2238\nDocument end\n']","In 2012, Amazon's Elastic Block Storage (EBS) service experienced several outages due to an electric outage. The main problem originated from Amazon's U.S. East data center in Virginia, which is the biggest and oldest data center. The proposed fix for this issue is to perform major upgrades on the U.S. East data center to prevent the services from going down in the future.",reasoning,0.9999999999,1.0,1.0,0.9348951275957792,0.9967040798900392 +What was the 2012 issue with Amazon's EBS and its proposed fix?,entity search+vector,"The 2012 issue with Amazon's Elastic Block Storage (EBS) was related to service downtime caused by an electric outage at Amazon's U.S. East data center in Virginia. To address this problem and prevent future service disruptions, Amazon planned major upgrades on the U.S. East data center. These upgrades were crucial to avoid inconveniences and discomfort for customers relying on Amazon's services.","[""Document start\nThis Document belongs to the source unknown\nContent: chunks:\n- \t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n- influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n- \t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\ncommunities:\n- Neo4j is a comprehensive graph database management system that offers a wide range of products, services, and resources to support graph data science and related applications. It provides various deployment options, including Cloud Managed Services, Self-Hosted, and Graph-As-A-Service, with Amazon AWS as a cloud provider. Neo4j's offerings include the Neo4j Graph Data Science product, Neo4j GraphQL Library, Neo4j Workspace, Neo4j Bloom visualization tool, Neo4j Developer Tools, and Neo4j Data Connectors, all of which are integral parts of the Neo4j ecosystem.\n\nThe organization supports learning and development through resources like Graphacademy, which offers free online courses and certifications, and the Neo4j Blog for daily insights. It also provides a Resource Library with white papers and data sheets, Case Studies showcasing customer success stories, and Executive Insights on graph technology.\n\nNeo4j hosts various events, including the Neo4j Events Hub for live and on-demand training, webinars, and demos, the quarterly online conference Connections, and the global Graphsummit tour. The Cypher query language is a key technology used within Neo4j for exploring and manipulating graph data.\n\nAdditionally, Neo4j includes a company structure with information about its culture, diversity, leadership, and partnerships, offering opportunities to find or become a partner through its Partner Portal.\n- Alphabet is a major organization that serves as the parent company to several subsidiaries, including Verily, Waymo, Google Cloud, and YouTube. Ruth Porat holds the position of Chief Financial Officer (CFO) at Alphabet. Additionally, DeepMind is reported as part of Alphabet and also functions as a subsidiary. This network of companies highlights Alphabet's diverse interests in technology, healthcare, and media.\n- Amazon is a rapidly growing multinational e-commerce retailer based in America with a significant international presence. It faces competition from major organizations such as eBay, Barnes and Noble, and Wal-Mart. eBay and Barnes and Noble are noted for their product breadth and geographic market coverage, while Wal-Mart is recognized as the world's largest retail chain, employing a cost leadership strategy.\n\nAmazon competes with eBay, which utilizes both cost leadership and differentiation strategies. Barnes and Noble also competes with Amazon, employing an integrated focused cost leadership/differentiation strategy. Wal-Mart, another competitor, uses a cost leadership approach.\n\nAmazon is actively investing in various technologies and products, including video content, cloud services, and its Kindle product. It utilizes technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations. The company has also released a smartphone app and is located at the U.S. East Data Center.\n\nAmazon sees opportunities in emerging markets like China, which has a large population and growing disposable income. It is focused on capturing the global market and has invested in distribution centers to support this goal. The company discloses information about online sales taxes and is regulated by the Federal Trade Commission. Additionally, it receives support from the International Consumer Protection and Enforcement Network.\nentities:\n- Location:U.S. East Data Center \n- Technology:Elastic Block Storage (Ebs) \n- Company:Amazon Aws \n- Organization:Amazon Cooperation Treaty Organization \n- Organization:Google Cloud \n- Product:Deployment Center Get started. Download, integrate, and deploy.\n- Azure \n- Technology:Cloud \n- Organization:Amazon Fastest-growing, multinational e-commerce retailer in America with international presence.\n- Concept:Modern Tech Support \nrelationships:\n- Amazon LOCATED_AT U.S. East Data Center\n- Amazon USES Elastic Block Storage (Ebs)\n- Amazon INVESTS_IN Cloud\noutside:\n nodes:\n - Organization:Barnes And Noble Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.\n - Organization:Ebay Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.\n - Organization:Wal-Mart World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.\n - Activity:Online Shopping \n - Organization:Federal Trade Commission \n - Software:Authorization Library Based on Azure or other 3rd party authorization stack.\n - Organization:International Consumer Protection And Enforcement Network \n - Country:India Emerging country with large population and growing disposable income.\n - Organization:Alphabet \n - Organization:Neo4J A graph database management system.\n relationships:\n - Organization:Amazon COMPETITOR Organization:Barnes And Noble\n - Organization:Barnes And Noble COMPETES_WITH Organization:Amazon\n - Organization:Amazon COMPETES_WITH Organization:Barnes And Noble\n - Organization:Amazon COMPETITOR Organization:Ebay\n - Organization:Ebay COMPETES_WITH Organization:Amazon\n - Organization:Amazon COMPETES_WITH Organization:Ebay\n - Organization:Amazon COMPETITOR Organization:Wal-Mart\n - Organization:Amazon COMPETES_WITH Organization:Wal-Mart\n - Organization:Amazon BENEFIT Activity:Online Shopping\n - Concept:Modern Tech Support FACILITATES Activity:Online Shopping\n - Organization:Federal Trade Commission REGULATES Organization:Amazon\n - Software:Authorization Library BASED_ON Azure\n - Organization:International Consumer Protection And Enforcement Network SUPPORTS Organization:Amazon\n - Organization:Amazon OPPORTUNITY Country:India\n - Organization:Alphabet SUBSIDIARY Organization:Google Cloud\n - Company:Amazon Aws CLOUD_PROVIDER Organization:Neo4J\n\nDocument end\n""]","In 2012, Amazon's Elastic Block Storage (EBS) service experienced several outages due to an electric outage. The main problem originated from Amazon's U.S. East data center in Virginia, which is the biggest and oldest data center. The proposed fix for this issue is to perform major upgrades on the U.S. East data center to prevent the services from going down in the future.",reasoning,0.9999999999,1.0,0.6666666666666666,0.9683981941081358,0.8442264233747876 +What was the 2012 issue with Amazon's EBS and its proposed fix?,graph+vector,"In 2012, Amazon faced issues with its Elastic Block Storage (EBS) service due to an electric outage at the U.S. East data center in Virginia. The outage was primarily caused by problems in this data center, which is the largest and oldest, leading to service disruptions. To prevent such incidents in the future and avoid inconveniencing customers, Amazon planned major upgrades for the U.S. East data center.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: Text Content:\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Shivam Dube PLAYER Country:India\nPerson:Tristan Landrecht MEMBER Course:Bus 478\nPerson:Virat Kohli PLAYER Country:India\nPerson:Yashasvi Jaiswal PLAYER Country:India\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: Text Content:\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Shivam Dube PLAYER Country:India\nPerson:Tristan Landrecht MEMBER Course:Bus 478\nPerson:Virat Kohli PLAYER Country:India\nPerson:Yashasvi Jaiswal PLAYER Country:India\nDocument end\n\n\nDocument start\nThis Document belongs to the source github-recovery-codes.txt\nContent: Text Content:\ne6b17-50e48\n----\ne5ab9-b2238\n----\nEntities:\nUnknown:25A0D-3Bed5Df476-8C8Ade6B17-50E48F0A6C-E36E6\nUnknown:5E24C-D96Aad5029-Ca4B7Bc7F7-Edaeee5Ab9-B2238\n----\nRelationships:\n\nDocument end\n']","In 2012, Amazon's Elastic Block Storage (EBS) service experienced several outages due to an electric outage. The main problem originated from Amazon's U.S. East data center in Virginia, which is the biggest and oldest data center. The proposed fix for this issue is to perform major upgrades on the U.S. East data center to prevent the services from going down in the future.",reasoning,0.9999999999,1.0,1.0,0.9348775117397056,0.9965557282468844 +What was the 2012 issue with Amazon's EBS and its proposed fix?,graph+vector+fulltext,"In 2012, Amazon faced issues with its Elastic Block Storage (EBS) service due to an electric outage at the U.S. East data center in Virginia. The outage was primarily caused by problems at this data center, which is the largest and oldest, leading to service disruptions. To prevent such incidents in the future and avoid inconvenience to customers, Amazon planned major upgrades for the U.S. East data center.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: Text Content:\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Shivam Dube PLAYER Country:India\nPerson:Tristan Landrecht MEMBER Course:Bus 478\nPerson:Virat Kohli PLAYER Country:India\nPerson:Yashasvi Jaiswal PLAYER Country:India\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: Text Content:\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Shivam Dube PLAYER Country:India\nPerson:Tristan Landrecht MEMBER Course:Bus 478\nPerson:Virat Kohli PLAYER Country:India\nPerson:Yashasvi Jaiswal PLAYER Country:India\nDocument end\n\n\nDocument start\nThis Document belongs to the source github-recovery-codes.txt\nContent: Text Content:\ne6b17-50e48\n----\ne5ab9-b2238\n----\nEntities:\nUnknown:25A0D-3Bed5Df476-8C8Ade6B17-50E48F0A6C-E36E6\nUnknown:5E24C-D96Aad5029-Ca4B7Bc7F7-Edaeee5Ab9-B2238\n----\nRelationships:\n\nDocument end\n']","In 2012, Amazon's Elastic Block Storage (EBS) service experienced several outages due to an electric outage. The main problem originated from Amazon's U.S. East data center in Virginia, which is the biggest and oldest data center. The proposed fix for this issue is to perform major upgrades on the U.S. East data center to prevent the services from going down in the future.",reasoning,0.9999999999,1.0,1.0,0.9349194337018917,0.9466832748148085 +What strategy led to Amazon's growth from a small bookstore to a $48B retail giant?,vector,"Amazon's growth from a small online bookstore to a $48 billion retail giant was primarily fueled by a strategic shift in their business approach. Initially focusing on being the ""world's largest bookstore,"" Amazon later transitioned to a mergers and acquisitions strategy, expanding into various product categories and leveraging technological advancements. This shift allowed Amazon to evolve into a comprehensive online platform offering a wide range of products, emphasizing low prices, convenience, selection, and availability. Additionally, Amazon's ability to adapt to changing consumer behaviors, exploit emerging markets like China and India, and capitalize on the power of e-commerce and technological progress were key factors in its remarkable growth trajectory.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: \t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: \t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \nDocument end\n']","Amazon's growth from a small bookstore to a $48 billion retail giant was largely due to its transformation of corporate-level strategy into a mergers and acquisitions approach. Additionally, Amazon's goal to be a place where a customer can purchase anything online, and the advancements in technology such as computational power, bandwidth and data storage, also contributed to its growth.",reasoning,0.9999999999,1.0,1.0,0.9584663569619937,0.6703444617276766 +What strategy led to Amazon's growth from a small bookstore to a $48B retail giant?,fulltext,"Amazon's growth from a small online bookstore to a $48 billion retail giant was primarily fueled by a strategic shift in their corporate-level strategy towards mergers and acquisitions. This approach, coupled with a focus on technological progress, allowed Amazon to transform into a diversified platform offering a wide range of products across various categories. By leveraging computational power, bandwidth, data storage technologies, and investing in distribution centers, Amazon expanded its offerings, improved efficiency, and enhanced customer experience, ultimately driving its significant growth and success in the retail industry.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: \t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: \t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \nDocument end\n']","Amazon's growth from a small bookstore to a $48 billion retail giant was largely due to its transformation of corporate-level strategy into a mergers and acquisitions approach. Additionally, Amazon's goal to be a place where a customer can purchase anything online, and the advancements in technology such as computational power, bandwidth and data storage, also contributed to its growth.",reasoning,0.9999999999,1.0,1.0,0.961033547001144,0.9949075988542893 +What strategy led to Amazon's growth from a small bookstore to a $48B retail giant?,entity search+vector,"Amazon's growth from a small bookstore to a $48 billion retail giant can be attributed to several key strategies. Initially starting as an online bookstore, Amazon expanded its product offerings across more than forty categories, leveraging a customer-centric approach, continuous innovation, and strategic investments in technology. Jeff Bezos, the founder, played a pivotal role in driving Amazon's growth by focusing on customer experience, operational efficiency, and global market expansion. Additionally, Amazon's emphasis on long-term vision, diversification into cloud services, video content, and Kindle products, along with investments in distribution centers, contributed significantly to its rapid growth and success in the e-commerce industry.","[""Document start\nThis Document belongs to the source unknown\nContent: chunks:\n- providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n- \t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n- since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \ncommunities:\n- Amazon.com, founded in 1993 by Jeff Benzos, initially started as an online bookstore. Over the years, it has grown into a massive retail enterprise valued at $48 billion, offering products across more than forty categories. The company experienced significant growth momentum during the Dot-Com Bubble. Jeff Benzos, the founder, played a pivotal role in its development and expansion.\n- Amazon is a rapidly growing multinational e-commerce retailer based in America with a significant international presence. It faces competition from major organizations such as eBay, Barnes and Noble, and Wal-Mart. eBay and Barnes and Noble are noted for their product breadth and geographic market coverage, while Wal-Mart is recognized as the world's largest retail chain, employing a cost leadership strategy.\n\nAmazon competes with eBay, which utilizes both cost leadership and differentiation strategies. Barnes and Noble also competes with Amazon, employing an integrated focused cost leadership/differentiation strategy. Wal-Mart, another competitor, uses a cost leadership approach.\n\nAmazon is actively investing in various technologies and products, including video content, cloud services, and its Kindle product. It utilizes technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations. The company has also released a smartphone app and is located at the U.S. East Data Center.\n\nAmazon sees opportunities in emerging markets like China, which has a large population and growing disposable income. It is focused on capturing the global market and has invested in distribution centers to support this goal. The company discloses information about online sales taxes and is regulated by the Federal Trade Commission. Additionally, it receives support from the International Consumer Protection and Enforcement Network.\n- Amazon is a rapidly growing multinational e-commerce retailer based in America with a significant international presence. It faces competition from major organizations such as eBay, Barnes and Noble, and Wal-Mart. eBay and Barnes and Noble are noted for their product breadth and geographic market coverage, while Wal-Mart is recognized as the world's largest retail chain, employing a cost leadership strategy.\n\nAmazon competes with eBay, which utilizes both cost leadership and differentiation strategies. Barnes and Noble also competes with Amazon, employing an integrated focused cost leadership/differentiation strategy. Wal-Mart, another competitor, uses a cost leadership approach.\n\nAmazon is actively investing in various technologies and products, including video content, cloud services, and its Kindle product. It utilizes technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations. The company has also released a smartphone app and is located at the U.S. East Data Center.\n\nAmazon sees opportunities in emerging markets like China, which has a large population and growing disposable income. It is focused on capturing the global market and has invested in distribution centers to support this goal. The company discloses information about online sales taxes and is regulated by the Federal Trade Commission. Additionally, it receives support from the International Consumer Protection and Enforcement Network.\nentities:\n- Organization:Amazon Fastest-growing, multinational e-commerce retailer in America with international presence.\n- Company:Amazon.Com Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.\n- Organization:Barnes And Noble Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.\n- Organization:Wal-Mart World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.\n- Concept:E-Commerce \n- Concept:Bargaining_Power_Of_Buyers High because customers can choose among numerous online stores for the lowest price.\n- Electronic_Commerce_Firms \n- Online_Purchasing \n- Activity:Online Shopping \n- Online_Shopping \nrelationships:\n- Amazon COMPETITOR Barnes And Noble\n- Amazon COMPETES_WITH Barnes And Noble\n- Amazon COMPETITOR Wal-Mart\n- Amazon COMPETES_WITH Wal-Mart\n- Amazon BENEFIT Online Shopping\n- Barnes And Noble COMPETES_WITH Amazon\n- E-Commerce ENABLES Online Shopping\noutside:\n nodes:\n - Organization:Ebay Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.\n - Country:India Emerging country with large population and growing disposable income.\n - Technology:Elastic Block Storage (Ebs) \n - Country:China Emerging country with large population and growing disposable income.\n - Product:Video Content \n - Technology:Cloud \n - Organization:Federal Trade Commission \n - Product:Kindle \n - Location:Distribution Centers \n - Organization:International Consumer Protection And Enforcement Network \n relationships:\n - Organization:Amazon COMPETITOR Organization:Ebay\n - Organization:Ebay COMPETES_WITH Organization:Amazon\n - Organization:Amazon COMPETES_WITH Organization:Ebay\n - Organization:Amazon OPPORTUNITY Country:India\n - Organization:Amazon USES Technology:Elastic Block Storage (Ebs)\n - Organization:Amazon OPPORTUNITY Country:China\n - Organization:Amazon INVESTS_IN Product:Video Content\n - Organization:Amazon INVESTS_IN Technology:Cloud\n - Organization:Federal Trade Commission REGULATES Organization:Amazon\n - Organization:Amazon INVESTS_IN Product:Kindle\n - Organization:Amazon INVESTS_IN Location:Distribution Centers\n - Organization:International Consumer Protection And Enforcement Network SUPPORTS Organization:Amazon\n\nDocument end\n""]","Amazon's growth from a small bookstore to a $48 billion retail giant was largely due to its transformation of corporate-level strategy into a mergers and acquisitions approach. Additionally, Amazon's goal to be a place where a customer can purchase anything online, and the advancements in technology such as computational power, bandwidth and data storage, also contributed to its growth.",reasoning,0.9999999999,0.0,0.5294117647058824,0.9620756699751561,0.9436288774421768 +What strategy led to Amazon's growth from a small bookstore to a $48B retail giant?,graph+vector,"Amazon's growth from a small online bookstore to a $48 billion retail giant was primarily fueled by a strategic shift towards mergers and acquisitions, coupled with a focus on technological progress. Initially starting as an online bookstore, Amazon transformed its corporate-level strategy into an approach that emphasized mergers and acquisitions, allowing it to expand rapidly. Additionally, Amazon leveraged advancements in computational power, bandwidth, and data storage technologies to diversify its product offerings, enhance customer experience, and scale its operations across various categories. These strategic moves enabled Amazon to evolve into a massive retail machine with a broad market presence and a valuation of $48 billion.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: Text Content:\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: Text Content:\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:\nDocument end\n']","Amazon's growth from a small bookstore to a $48 billion retail giant was largely due to its transformation of corporate-level strategy into a mergers and acquisitions approach. Additionally, Amazon's goal to be a place where a customer can purchase anything online, and the advancements in technology such as computational power, bandwidth and data storage, also contributed to its growth.",reasoning,0.9999999999,1.0,0.5333333333333333,0.9610932535289535,0.8788590318886854 +What strategy led to Amazon's growth from a small bookstore to a $48B retail giant?,graph+vector+fulltext,"Amazon's growth from a small bookstore to a $48 billion retail giant was primarily fueled by a strategic shift in their business approach. Initially focusing on online book sales, Amazon later transitioned to a mergers and acquisitions strategy, expanding into various product categories and leveraging technological advancements. This shift allowed Amazon to evolve into a comprehensive online platform offering a wide range of products, emphasizing low prices, convenience, selection, and availability. Additionally, Amazon's ability to adapt to emerging markets like China and India, along with investments in infrastructure and data storage technologies, played a crucial role in their remarkable growth trajectory.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: Text Content:\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: Text Content:\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:\nDocument end\n']","Amazon's growth from a small bookstore to a $48 billion retail giant was largely due to its transformation of corporate-level strategy into a mergers and acquisitions approach. Additionally, Amazon's goal to be a place where a customer can purchase anything online, and the advancements in technology such as computational power, bandwidth and data storage, also contributed to its growth.",reasoning,0.9999999999,1.0,1.0,0.96201214858725,0.8253596616571912 +What strategy led to Amazon's growth from a small bookstore to a $48B retail giant?,global search+vector+fulltext,"Amazon's growth from a small online bookstore to a $48 billion retail giant can be attributed to several key strategies. Initially, Amazon focused on providing a wide selection of products and convenient online shopping experiences. Jeff Bezos, the founder, emphasized customer satisfaction, efficient logistics, and continuous innovation. Amazon's strategic use of technology, like 1-Click Ordering and cloud services, also played a crucial role in streamlining operations and enhancing customer service. Additionally, Amazon's expansion into various product categories, investment in emerging markets like China, and strategic partnerships contributed significantly to its remarkable growth trajectory.","[""Document start\nThis Document belongs to the source unknown\nContent: Amazon is a rapidly growing multinational e-commerce retailer based in America with a significant international presence. It faces competition from major organizations such as eBay, Barnes and Noble, and Wal-Mart. eBay and Barnes and Noble are noted for their product breadth and geographic market coverage, while Wal-Mart is recognized as the world's largest retail chain, employing a cost leadership strategy.\n\nAmazon competes with eBay, which utilizes both cost leadership and differentiation strategies. Barnes and Noble also competes with Amazon, employing an integrated focused cost leadership/differentiation strategy. Wal-Mart, another competitor, uses a cost leadership approach.\n\nAmazon is actively investing in various technologies and products, including video content, cloud services, and its Kindle product. It utilizes technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations. The company has also released a smartphone app and is located at the U.S. East Data Center.\n\nAmazon sees opportunities in emerging markets like China, which has a large population and growing disposable income. It is focused on capturing the global market and has invested in distribution centers to support this goal. The company discloses information about online sales taxes and is regulated by the Federal Trade Commission. Additionally, it receives support from the International Consumer Protection and Enforcement Network.\n----\nThe community consists of a group of individuals, Jin Can Chen, Jae Kim, Jessica Zhang, John Chen, and Tristan Landrecht, who are enrolled in Bus 478, a seminar focused on business strategy. This course involves a collaborative or team-based approach, suggesting that these members work closely together on projects or discussions related to business strategy. Additionally, the community is linked to Amazon.com, a company founded in 1993 by Jeff Benzos. Originally an online bookstore, Amazon has evolved into a vast retail enterprise valued at $48 billion, offering a wide range of products across more than forty categories. The company saw substantial growth during the Dot-Com Bubble, with Jeff Benzos playing a crucial role in its expansion and success. This connection to Amazon may indicate that the course or group discussions could involve case studies or strategic analyses of Amazon's business model and growth trajectory.\n----\nAmazon.com, founded in 1993 by Jeff Benzos, initially started as an online bookstore. Over the years, it has grown into a massive retail enterprise valued at $48 billion, offering products across more than forty categories. The company experienced significant growth momentum during the Dot-Com Bubble. Jeff Benzos, the founder, played a pivotal role in its development and expansion.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offers a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, regulated by the Federal Trade Commission, and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offers a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, being regulated by the Federal Trade Commission and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offer a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, regulated by the Federal Trade Commission, and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nThe community consists of individuals and entities connected through educational and business endeavors. Jin Can Chen, Jae Kim, Jessica Zhang, John Chen, and Tristan Landrecht are all participants in Bus 478, a seminar focused on business strategy, which emphasizes teamwork and collaboration. This educational setting likely fosters skills relevant to business growth and strategy, akin to those demonstrated by Amazon.com. Founded in 1993 by Jeff Benzos, Amazon began as an online bookstore and evolved into a vast retail empire valued at $48 billion, offering a diverse range of products across more than forty categories. The company's significant expansion, particularly during the Dot-Com Bubble, highlights the importance of strategic business planning and leadership, as exemplified by Benzos' pivotal role in its success. This connection between the educational focus of Bus 478 and the business strategies employed by Amazon underscores the relevance of strategic thinking in both academic and real-world business contexts.\n----\nThe community consists of individuals and entities connected through educational and business endeavors. Jin Can Chen, Jae Kim, Jessica Zhang, John Chen, and Tristan Landrecht are all participants in Bus 478, a seminar focused on business strategy, which emphasizes teamwork and collaboration. This educational setting likely fosters skills relevant to business growth and strategy, akin to those demonstrated by Amazon.com. Founded in 1993 by Jeff Benzos, Amazon began as an online bookstore and evolved into a vast retail empire valued at $48 billion, offering a diverse range of products across more than forty categories. The company's significant expansion, particularly during the Dot-Com Bubble, highlights the importance of strategic business planning and leadership, as exemplified by Benzos' pivotal role in its success. This connection between the educational focus of Bus 478 and the business strategies employed by Amazon underscores the relevance of strategic thinking in both academic and real-world business contexts.\n----\nThe online shopping landscape is undergoing a transformative enhancement through the integration of 3D virtual technology, which aims to significantly elevate the consumer experience. This technological advancement is complemented by the widespread use of electronic devices, particularly smartphones, which are streamlining and simplifying transaction processes for online shoppers. Furthermore, emerging markets, notably China and India, are poised to play a pivotal role in the expansion of online shopping. These countries, characterized by their vast populations and rising disposable incomes, offer substantial opportunities for growth and development in the online retail sector.\n----\nThe online shopping landscape is undergoing a transformative enhancement through the integration of 3D virtual technology, which aims to significantly elevate the consumer experience. This technological advancement is complemented by the widespread use of electronic devices, particularly smartphones, which are streamlining and simplifying transaction processes for online shoppers. Furthermore, emerging markets, notably China and India, are poised to play a pivotal role in the expansion of online shopping. These countries, characterized by their vast populations and rising disposable incomes, offer substantial opportunities for growth and development in the online retail sector.\nDocument end\n""]","Amazon's growth from a small bookstore to a $48 billion retail giant was largely due to its transformation of corporate-level strategy into a mergers and acquisitions approach. Additionally, Amazon's goal to be a place where a customer can purchase anything online, and the advancements in technology such as computational power, bandwidth and data storage, also contributed to its growth.",reasoning,0.9999999999,0.0,0.6875,0.9583597742929056,0.7944593587522599 +What strategic shift helped Amazon evolve from a small bookstore to a $48B retail giant?,vector,"Amazon evolved from a small bookstore to a $48 billion retail giant by strategically shifting its corporate-level strategy towards mergers and acquisitions. This shift allowed Amazon to expand its business operations, diversify its offerings, and tap into new markets successfully. Additionally, Amazon leveraged technological progress, computational power, bandwidth, and data distribution centers to enhance its operations and scale up its business efficiently.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: \t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: \t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \nDocument end\n']",Amazon transformed their corporate-level strategy into a mergers and acquisitions approach.,reasoning,0.9999999999,1.0,0.7,0.9534779033321638,0.47546527728430277 +What strategic shift helped Amazon evolve from a small bookstore to a $48B retail giant?,fulltext,"Amazon evolved from a small bookstore to a $48 billion retail giant by strategically shifting its corporate-level strategy towards mergers and acquisitions. This approach allowed Amazon to expand its business operations, diversify its offerings, and tap into new markets successfully. Additionally, leveraging technological progress in areas like computational power, bandwidth, and data storage played a crucial role in Amazon's transformation and growth over the years.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: \t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n\t\r \xa0 0 BUS 478: Seminar on Business Strategy SYNOPSIS PROJECT: AMAZON.COM Group G Group Members: Tristan Landrecht Jessica Zhang John Chen Jin Can Chen Jae Kim \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: \t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n\t\r \xa0 0 BUS 478: Seminar on Business Strategy SYNOPSIS PROJECT: AMAZON.COM Group G Group Members: Tristan Landrecht Jessica Zhang John Chen Jin Can Chen Jae Kim \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\nDocument end\n']",Amazon transformed their corporate-level strategy into a mergers and acquisitions approach.,reasoning,0.9999999999,1.0,0.7142857142857143,0.9534779033321638,0.9758717973852911 +What strategic shift helped Amazon evolve from a small bookstore to a $48B retail giant?,entity search+vector,"Amazon evolved from a small bookstore to a $48 billion retail giant through strategic shifts such as diversification into various product categories, embracing technological advancements like cloud services and Kindle products, investing in distribution centers to support global expansion, and focusing on capturing emerging markets like China with growing disposable income. Additionally, Amazon's founder, Jeff Bezos, played a pivotal role in the company's development and expansion by driving innovation and customer-centric strategies.","[""Document start\nThis Document belongs to the source unknown\nContent: chunks:\n- providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n- \t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n- since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \ncommunities:\n- Amazon.com, founded in 1993 by Jeff Benzos, initially started as an online bookstore. Over the years, it has grown into a massive retail enterprise valued at $48 billion, offering products across more than forty categories. The company experienced significant growth momentum during the Dot-Com Bubble. Jeff Benzos, the founder, played a pivotal role in its development and expansion.\n- Amazon is a rapidly growing multinational e-commerce retailer based in America with a significant international presence. It faces competition from major organizations such as eBay, Barnes and Noble, and Wal-Mart. eBay and Barnes and Noble are noted for their product breadth and geographic market coverage, while Wal-Mart is recognized as the world's largest retail chain, employing a cost leadership strategy.\n\nAmazon competes with eBay, which utilizes both cost leadership and differentiation strategies. Barnes and Noble also competes with Amazon, employing an integrated focused cost leadership/differentiation strategy. Wal-Mart, another competitor, uses a cost leadership approach.\n\nAmazon is actively investing in various technologies and products, including video content, cloud services, and its Kindle product. It utilizes technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations. The company has also released a smartphone app and is located at the U.S. East Data Center.\n\nAmazon sees opportunities in emerging markets like China, which has a large population and growing disposable income. It is focused on capturing the global market and has invested in distribution centers to support this goal. The company discloses information about online sales taxes and is regulated by the Federal Trade Commission. Additionally, it receives support from the International Consumer Protection and Enforcement Network.\n- Amazon is a rapidly growing multinational e-commerce retailer based in America with a significant international presence. It faces competition from major organizations such as eBay, Barnes and Noble, and Wal-Mart. eBay and Barnes and Noble are noted for their product breadth and geographic market coverage, while Wal-Mart is recognized as the world's largest retail chain, employing a cost leadership strategy.\n\nAmazon competes with eBay, which utilizes both cost leadership and differentiation strategies. Barnes and Noble also competes with Amazon, employing an integrated focused cost leadership/differentiation strategy. Wal-Mart, another competitor, uses a cost leadership approach.\n\nAmazon is actively investing in various technologies and products, including video content, cloud services, and its Kindle product. It utilizes technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations. The company has also released a smartphone app and is located at the U.S. East Data Center.\n\nAmazon sees opportunities in emerging markets like China, which has a large population and growing disposable income. It is focused on capturing the global market and has invested in distribution centers to support this goal. The company discloses information about online sales taxes and is regulated by the Federal Trade Commission. Additionally, it receives support from the International Consumer Protection and Enforcement Network.\nentities:\n- Organization:Amazon Fastest-growing, multinational e-commerce retailer in America with international presence.\n- Organization:Barnes And Noble Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.\n- Company:Amazon.Com Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.\n- Organization:Wal-Mart World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.\n- Electronic_Commerce_Firms \n- Concept:E-Commerce \n- Concept:Bargaining_Power_Of_Buyers High because customers can choose among numerous online stores for the lowest price.\n- Online_Shopping \n- Activity:Online Shopping \n- Online_Purchasing \nrelationships:\n- Amazon COMPETITOR Barnes And Noble\n- Amazon COMPETES_WITH Barnes And Noble\n- Amazon COMPETITOR Wal-Mart\n- Amazon COMPETES_WITH Wal-Mart\n- Amazon BENEFIT Online Shopping\n- Barnes And Noble COMPETES_WITH Amazon\n- E-Commerce ENABLES Online Shopping\noutside:\n nodes:\n - Organization:Ebay Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.\n - Country:India Emerging country with large population and growing disposable income.\n - Technology:Elastic Block Storage (Ebs) \n - Country:China Emerging country with large population and growing disposable income.\n - Product:Video Content \n - Technology:Cloud \n - Organization:Federal Trade Commission \n - Product:Kindle \n - Location:Distribution Centers \n - Organization:International Consumer Protection And Enforcement Network \n relationships:\n - Organization:Amazon COMPETITOR Organization:Ebay\n - Organization:Ebay COMPETES_WITH Organization:Amazon\n - Organization:Amazon COMPETES_WITH Organization:Ebay\n - Organization:Amazon OPPORTUNITY Country:India\n - Organization:Amazon USES Technology:Elastic Block Storage (Ebs)\n - Organization:Amazon OPPORTUNITY Country:China\n - Organization:Amazon INVESTS_IN Product:Video Content\n - Organization:Amazon INVESTS_IN Technology:Cloud\n - Organization:Federal Trade Commission REGULATES Organization:Amazon\n - Organization:Amazon INVESTS_IN Product:Kindle\n - Organization:Amazon INVESTS_IN Location:Distribution Centers\n - Organization:International Consumer Protection And Enforcement Network SUPPORTS Organization:Amazon\n\nDocument end\n""]",Amazon transformed their corporate-level strategy into a mergers and acquisitions approach.,reasoning,0.0,0.0,0.9,0.9534664131070926,0.8910963069767317 +What strategic shift helped Amazon evolve from a small bookstore to a $48B retail giant?,graph+vector,"Amazon evolved from a small bookstore to a $48 billion retail giant by strategically shifting its corporate-level strategy towards mergers and acquisitions. This shift allowed Amazon to expand its business beyond books and transform into a diverse retail platform offering products in over forty categories. Additionally, leveraging technological progress in computational power, bandwidth, and data storage enabled Amazon to scale its operations and become a significant player in the e-commerce industry.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: Text Content:\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Sales_Taxes\n:Smartphone_App\nActivity:Online Shopping\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\nTechnology:Internet\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Shivam Dube PLAYER Country:India\nPerson:Tristan Landrecht\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: Text Content:\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Sales_Taxes\n:Smartphone_App\nActivity:Online Shopping\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\nTechnology:Internet\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Shivam Dube PLAYER Country:India\nPerson:Tristan Landrecht\nDocument end\n']",Amazon transformed their corporate-level strategy into a mergers and acquisitions approach.,reasoning,0.9999999999,1.0,1.0,0.9534664131070926,0.9737308895318777 +What strategic shift helped Amazon evolve from a small bookstore to a $48B retail giant?,graph+vector+fulltext,"Amazon evolved from a small bookstore to a $48 billion retail giant by strategically shifting its focus from being just an online bookstore to becoming a one-stop shop for almost anything online. Initially slow growth was overcome by leveraging the momentum from the dot-com bubble. Amazon transformed its corporate-level strategy into mergers and acquisitions, expanding its offerings and services. This shift allowed Amazon to capitalize on technological progress, invest in infrastructure, and enhance its core competencies to capture a significant share of the global market.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: Text Content:\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Sales_Taxes\n:Smartphone_App\nActivity:Online Shopping\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\nTechnology:Internet\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Shivam Dube PLAYER Country:India\nPerson:Tristan Landrecht\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: Text Content:\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Sales_Taxes\n:Smartphone_App\nActivity:Online Shopping\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\nTechnology:Internet\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Shivam Dube PLAYER Country:India\nPerson:Tristan Landrecht\nDocument end\n']",Amazon transformed their corporate-level strategy into a mergers and acquisitions approach.,reasoning,0.9999999999,1.0,0.6,0.953534996984493,0.4557118485937385 +What strategic shift helped Amazon evolve from a small bookstore to a $48B retail giant?,global search+vector+fulltext,"Amazon's strategic shift from a small online bookstore to a $48 billion retail giant was primarily driven by its focus on strategic business planning, leadership, and continuous innovation. Jeff Bezos, the founder of Amazon, played a pivotal role in this transformation by emphasizing customer-centric strategies, diversifying product offerings across more than forty categories, and leveraging the growth opportunities presented during the Dot-Com Bubble. Amazon's ability to adapt, expand its product range, invest in technology, and prioritize customer experience were key factors in its remarkable evolution and success.","[""Document start\nThis Document belongs to the source unknown\nContent: The community consists of individuals and entities connected through educational and business endeavors. Jin Can Chen, Jae Kim, Jessica Zhang, John Chen, and Tristan Landrecht are all participants in Bus 478, a seminar focused on business strategy, which emphasizes teamwork and collaboration. This educational setting likely fosters skills relevant to business growth and strategy, akin to those demonstrated by Amazon.com. Founded in 1993 by Jeff Benzos, Amazon began as an online bookstore and evolved into a vast retail empire valued at $48 billion, offering a diverse range of products across more than forty categories. The company's significant expansion, particularly during the Dot-Com Bubble, highlights the importance of strategic business planning and leadership, as exemplified by Benzos' pivotal role in its success. This connection between the educational focus of Bus 478 and the business strategies employed by Amazon underscores the relevance of strategic thinking in both academic and real-world business contexts.\n----\nThe community consists of a group of individuals, Jin Can Chen, Jae Kim, Jessica Zhang, John Chen, and Tristan Landrecht, who are enrolled in Bus 478, a seminar focused on business strategy. This course involves a collaborative or team-based approach, suggesting that these members work closely together on projects or discussions related to business strategy. Additionally, the community is linked to Amazon.com, a company founded in 1993 by Jeff Benzos. Originally an online bookstore, Amazon has evolved into a vast retail enterprise valued at $48 billion, offering a wide range of products across more than forty categories. The company saw substantial growth during the Dot-Com Bubble, with Jeff Benzos playing a crucial role in its expansion and success. This connection to Amazon may indicate that the course or group discussions could involve case studies or strategic analyses of Amazon's business model and growth trajectory.\n----\nThe community consists of individuals and entities connected through educational and business endeavors. Jin Can Chen, Jae Kim, Jessica Zhang, John Chen, and Tristan Landrecht are all participants in Bus 478, a seminar focused on business strategy, which emphasizes teamwork and collaboration. This educational setting likely fosters skills relevant to business growth and strategy, akin to those demonstrated by Amazon.com. Founded in 1993 by Jeff Benzos, Amazon began as an online bookstore and evolved into a vast retail empire valued at $48 billion, offering a diverse range of products across more than forty categories. The company's significant expansion, particularly during the Dot-Com Bubble, highlights the importance of strategic business planning and leadership, as exemplified by Benzos' pivotal role in its success. This connection between the educational focus of Bus 478 and the business strategies employed by Amazon underscores the relevance of strategic thinking in both academic and real-world business contexts.\n----\nAmazon.com, founded in 1993 by Jeff Benzos, initially started as an online bookstore. Over the years, it has grown into a massive retail enterprise valued at $48 billion, offering products across more than forty categories. The company experienced significant growth momentum during the Dot-Com Bubble. Jeff Benzos, the founder, played a pivotal role in its development and expansion.\n----\nAmazon is a rapidly growing multinational e-commerce retailer based in America with a significant international presence. It faces competition from major organizations such as eBay, Barnes and Noble, and Wal-Mart. eBay and Barnes and Noble are noted for their product breadth and geographic market coverage, while Wal-Mart is recognized as the world's largest retail chain, employing a cost leadership strategy.\n\nAmazon competes with eBay, which utilizes both cost leadership and differentiation strategies. Barnes and Noble also competes with Amazon, employing an integrated focused cost leadership/differentiation strategy. Wal-Mart, another competitor, uses a cost leadership approach.\n\nAmazon is actively investing in various technologies and products, including video content, cloud services, and its Kindle product. It utilizes technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations. The company has also released a smartphone app and is located at the U.S. East Data Center.\n\nAmazon sees opportunities in emerging markets like China, which has a large population and growing disposable income. It is focused on capturing the global market and has invested in distribution centers to support this goal. The company discloses information about online sales taxes and is regulated by the Federal Trade Commission. Additionally, it receives support from the International Consumer Protection and Enforcement Network.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offers a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, being regulated by the Federal Trade Commission and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offers a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, regulated by the Federal Trade Commission, and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offer a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, regulated by the Federal Trade Commission, and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nThe online shopping landscape is undergoing a transformative enhancement through the integration of 3D virtual technology, which aims to significantly elevate the consumer experience. This technological advancement is complemented by the widespread use of electronic devices, particularly smartphones, which are streamlining and simplifying transaction processes for online shoppers. Furthermore, emerging markets, notably China and India, are poised to play a pivotal role in the expansion of online shopping. These countries, characterized by their vast populations and rising disposable incomes, offer substantial opportunities for growth and development in the online retail sector.\n----\nThe online shopping landscape is undergoing a transformative enhancement through the integration of 3D virtual technology, which aims to significantly elevate the consumer experience. This technological advancement is complemented by the widespread use of electronic devices, particularly smartphones, which are streamlining and simplifying transaction processes for online shoppers. Furthermore, emerging markets, notably China and India, are poised to play a pivotal role in the expansion of online shopping. These countries, characterized by their vast populations and rising disposable incomes, offer substantial opportunities for growth and development in the online retail sector.\nDocument end\n""]",Amazon transformed their corporate-level strategy into a mergers and acquisitions approach.,reasoning,0.0,0.0,0.6153846153846154,0.9564108581225913,0.7824061935944068 +"How has Amazon's M and A strategy, transitioning from an online bookstore to a multi-category platform, been shaped by competition?",vector,"Amazon's mergers and acquisitions (M&A) strategy evolved as a response to competition in the e-commerce industry. Initially known as an online bookstore, Amazon faced intense rivalry from competitors like eBay, Barnes and Noble, and Wal-Mart. To stay competitive, Amazon expanded its business model to become a multi-category platform offering a wide range of products. This strategic shift was influenced by the need to differentiate itself and maintain a competitive edge in the market. By diversifying its offerings through acquisitions and mergers, Amazon aimed to enhance its competitive position and cater to a broader customer base beyond just books.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \nDocument end\n']","The context does not provide specific information on how Amazon's M&A strategy, transitioning from an online bookstore to a multi-category platform, has been shaped by competition.",multi_context,0.0,1.0,0.5555555555555556,0.9315804599105225,0.8393456041533853 +"How has Amazon's M and A strategy, transitioning from an online bookstore to a multi-category platform, been shaped by competition?",fulltext,"Amazon's mergers and acquisitions (M&A) strategy, transitioning from an online bookstore to a multi-category platform, has been significantly influenced by competition. As Amazon faced intense rivalry among competing firms, especially from major competitors like eBay, Barnes and Noble, and Wal-Mart, it strategically expanded its offerings through acquisitions to stay competitive. By diversifying into various categories beyond books, Amazon aimed to differentiate itself and maintain its market position amidst the high competition in the e-commerce industry. This strategic shift allowed Amazon to leverage its core competencies and adapt to changing consumer preferences, ultimately driving its growth and success as a multi-category platform.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \nDocument end\n']","The context does not provide specific information on how Amazon's M&A strategy, transitioning from an online bookstore to a multi-category platform, has been shaped by competition.",multi_context,0.0,1.0,0.5454545454545454,0.9308140201045719,0.4373952418942165 +"How has Amazon's M and A strategy, transitioning from an online bookstore to a multi-category platform, been shaped by competition?",entity search+vector,"Amazon's M&A strategy, evolving from an online bookstore to a diverse multi-category platform, has been significantly influenced by competition. Competitors like eBay, Barnes and Noble, and Wal-Mart have played a crucial role in shaping Amazon's expansion. The competitive landscape has driven Amazon to diversify its offerings, invest in new technologies like cloud services and video content, and expand into emerging markets like China and India. This strategic response to competition has propelled Amazon's growth and transformation into a retail giant across various product categories.","[""Document start\nThis Document belongs to the source unknown\nContent: chunks:\n- \t\r \xa0 3 online payment methods such as online banking and PayPal create more convenience in purchase transactions, which in turn enhances customers’ online shopping experience. Also, the invention of electronic devices such as smartphones deliver easy and convenient transaction processes, further facilitating online shopping. For instance, Amazon recently released a smartphone app for their Kindle services, allowing users to conveniently access the online sales platform and review products before purchasing. In the future, the use of 3D virtual technology to market products will also take online shopping to new heights. Political/Legal In the modern day environment, firms must be cautious when they deal with international policies on online distribution. In the U.S., electronic commerce firms are regulated by the Federal Trade Commission, which regulates online advertising and the security of consumers’ personal information. On the other hand, International Consumer Protection and Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions \n- Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers. Demographic As the world’s population is aging rapidly, baby boomers are moving towards retirement so that they will have weaker purchasing power. Thus, generation X and Y have become companies’ target markets for product selling. These generations are technologically adept and tend to engage more in online purchasing. Based on a survey, 62 percent of Generation Y liked to purchase things online, as compared to 32 percent of those aged older than 50. Organizations \n- providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \ncommunities:\n- Neo4j is a comprehensive graph database management system that offers a wide range of products, services, and resources to support graph data science and related applications. It provides various deployment options, including Cloud Managed Services, Self-Hosted, and Graph-As-A-Service, with Amazon AWS as a cloud provider. Neo4j's offerings include the Neo4j Graph Data Science product, Neo4j GraphQL Library, Neo4j Workspace, Neo4j Bloom visualization tool, Neo4j Developer Tools, and Neo4j Data Connectors, all of which are integral parts of the Neo4j ecosystem.\n\nThe organization supports learning and development through resources like Graphacademy, which offers free online courses and certifications, and the Neo4j Blog for daily insights. It also provides a Resource Library with white papers and data sheets, Case Studies showcasing customer success stories, and Executive Insights on graph technology.\n\nNeo4j hosts various events, including the Neo4j Events Hub for live and on-demand training, webinars, and demos, the quarterly online conference Connections, and the global Graphsummit tour. The Cypher query language is a key technology used within Neo4j for exploring and manipulating graph data.\n\nAdditionally, Neo4j includes a company structure with information about its culture, diversity, leadership, and partnerships, offering opportunities to find or become a partner through its Partner Portal.\n- Amazon.com, founded in 1993 by Jeff Benzos, initially started as an online bookstore. Over the years, it has grown into a massive retail enterprise valued at $48 billion, offering products across more than forty categories. The company experienced significant growth momentum during the Dot-Com Bubble. Jeff Benzos, the founder, played a pivotal role in its development and expansion.\n- Amazon is a rapidly growing multinational e-commerce retailer based in America with a significant international presence. It faces competition from major organizations such as eBay, Barnes and Noble, and Wal-Mart. eBay and Barnes and Noble are noted for their product breadth and geographic market coverage, while Wal-Mart is recognized as the world's largest retail chain, employing a cost leadership strategy.\n\nAmazon competes with eBay, which utilizes both cost leadership and differentiation strategies. Barnes and Noble also competes with Amazon, employing an integrated focused cost leadership/differentiation strategy. Wal-Mart, another competitor, uses a cost leadership approach.\n\nAmazon is actively investing in various technologies and products, including video content, cloud services, and its Kindle product. It utilizes technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations. The company has also released a smartphone app and is located at the U.S. East Data Center.\n\nAmazon sees opportunities in emerging markets like China, which has a large population and growing disposable income. It is focused on capturing the global market and has invested in distribution centers to support this goal. The company discloses information about online sales taxes and is regulated by the Federal Trade Commission. Additionally, it receives support from the International Consumer Protection and Enforcement Network.\nentities:\n- Organization:Amazon Cooperation Treaty Organization \n- Company:Amazon Aws \n- Electronic_Commerce_Firms \n- Organization:Amazon Fastest-growing, multinational e-commerce retailer in America with international presence.\n- Concept:Bargaining_Power_Of_Suppliers Low due to the substantial number of suppliers and the vast online global distribution network.\n- Concept:Bargaining_Power_Of_Buyers High because customers can choose among numerous online stores for the lowest price.\n- Concept:E-Commerce \n- Company:Amazon.Com Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.\n- Global_Market \n- Online_Purchasing \nrelationships:\n- Amazon CAPTURES Global_Market\noutside:\n nodes:\n - Organization:Barnes And Noble Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.\n - Organization:Ebay Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.\n - Organization:Wal-Mart World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.\n - Activity:Online Shopping \n - Country:India Emerging country with large population and growing disposable income.\n - Organization:Federal Trade Commission \n - Organization:International Consumer Protection And Enforcement Network \n - Organization:Federal_Trade_Commission Regulates online advertising and the security of consumers’ personal information in the U.S.\n - Country:China Emerging country with large population and growing disposable income.\n - Organization:Neo4J A graph database management system.\n relationships:\n - Organization:Amazon COMPETITOR Organization:Barnes And Noble\n - Organization:Barnes And Noble COMPETES_WITH Organization:Amazon\n - Organization:Amazon COMPETES_WITH Organization:Barnes And Noble\n - Organization:Amazon COMPETITOR Organization:Ebay\n - Organization:Ebay COMPETES_WITH Organization:Amazon\n - Organization:Amazon COMPETES_WITH Organization:Ebay\n - Organization:Amazon COMPETITOR Organization:Wal-Mart\n - Organization:Amazon COMPETES_WITH Organization:Wal-Mart\n - Organization:Amazon BENEFIT Activity:Online Shopping\n - Concept:E-Commerce ENABLES Activity:Online Shopping\n - Organization:Amazon OPPORTUNITY Country:India\n - Organization:Federal Trade Commission REGULATES Organization:Amazon\n - Organization:International Consumer Protection And Enforcement Network SUPPORTS Organization:Amazon\n - Organization:Federal_Trade_Commission REGULATES Electronic_Commerce_Firms\n - Organization:Amazon OPPORTUNITY Country:China\n - Company:Amazon Aws CLOUD_PROVIDER Organization:Neo4J\n\nDocument end\n""]","The context does not provide specific information on how Amazon's M&A strategy, transitioning from an online bookstore to a multi-category platform, has been shaped by competition.",multi_context,0.0,1.0,0.25,0.9415222169452915,0.5234713306082578 +"How has Amazon's M and A strategy, transitioning from an online bookstore to a multi-category platform, been shaped by competition?",graph+vector,"Amazon's mergers and acquisitions (M&A) strategy, transitioning from an online bookstore to a multi-category platform, has been significantly influenced by competition. As Amazon faced intense rivalry among competing firms, especially from major competitors like eBay, Barnes and Noble, and Wal-Mart, it strategically expanded its offerings through acquisitions to stay competitive. By acquiring companies in various categories, Amazon diversified its product range, enhanced its market presence, and strengthened its competitive position in the face of substitutes and increasing competition in the e-commerce industry.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: Text Content:\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Shivam Dube PLAYER Country:India\n\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: Text Content:\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Shivam Dube PLAYER Country:India\n\nDocument end\n']","The context does not provide specific information on how Amazon's M&A strategy, transitioning from an online bookstore to a multi-category platform, has been shaped by competition.",multi_context,0.0,1.0,0.375,0.9380030186858774,0.522217312685086 +"How has Amazon's M and A strategy, transitioning from an online bookstore to a multi-category platform, been shaped by competition?",graph+vector+fulltext,"Amazon's mergers and acquisitions (M&A) strategy, transitioning from an online bookstore to a multi-category platform, has been significantly influenced by competition. As Amazon faced intense rivalry among competing firms, especially from major competitors like eBay, Barnes and Noble, and Wal-Mart, it strategically expanded its offerings through acquisitions to stay competitive. By diversifying into various categories beyond books, Amazon aimed to differentiate itself and maintain its market position. This strategic shift allowed Amazon to leverage its core competencies, adapt to changing consumer preferences, and enhance its competitive advantage in the evolving e-commerce landscape.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: Text Content:\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Shivam Dube PLAYER Country:India\n\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: Text Content:\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Shivam Dube PLAYER Country:India\n\nDocument end\n']","The context does not provide specific information on how Amazon's M&A strategy, transitioning from an online bookstore to a multi-category platform, has been shaped by competition.",multi_context,0.0,1.0,0.6363636363636364,0.9309101016692881,0.43721641843356046 +"How has Amazon's M and A strategy, transitioning from an online bookstore to a multi-category platform, been shaped by competition?",global search+vector+fulltext,"Amazon's mergers and acquisitions (M&A) strategy, evolving from an online bookstore to a diverse multi-category platform, has been significantly influenced by competition. The competitive landscape with major players like eBay, Barnes and Noble, and Wal-Mart has prompted Amazon to strategically expand its offerings through acquisitions to stay ahead. By observing competitors' strategies, Amazon has diversified its product range, invested in technologies like Elastic Block Storage (EBS) and cloud services, and expanded into emerging markets like China. This competitive environment has driven Amazon to innovate, acquire new capabilities, and enhance its market presence to effectively compete and lead in the e-commerce industry.","[""Document start\nThis Document belongs to the source unknown\nContent: Amazon is a rapidly growing multinational e-commerce retailer based in America with a significant international presence. It faces competition from major organizations such as eBay, Barnes and Noble, and Wal-Mart. eBay and Barnes and Noble are noted for their product breadth and geographic market coverage, while Wal-Mart is recognized as the world's largest retail chain, employing a cost leadership strategy.\n\nAmazon competes with eBay, which utilizes both cost leadership and differentiation strategies. Barnes and Noble also competes with Amazon, employing an integrated focused cost leadership/differentiation strategy. Wal-Mart, another competitor, uses a cost leadership approach.\n\nAmazon is actively investing in various technologies and products, including video content, cloud services, and its Kindle product. It utilizes technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations. The company has also released a smartphone app and is located at the U.S. East Data Center.\n\nAmazon sees opportunities in emerging markets like China, which has a large population and growing disposable income. It is focused on capturing the global market and has invested in distribution centers to support this goal. The company discloses information about online sales taxes and is regulated by the Federal Trade Commission. Additionally, it receives support from the International Consumer Protection and Enforcement Network.\n----\nThe community consists of a group of individuals, Jin Can Chen, Jae Kim, Jessica Zhang, John Chen, and Tristan Landrecht, who are enrolled in Bus 478, a seminar focused on business strategy. This course involves a collaborative or team-based approach, suggesting that these members work closely together on projects or discussions related to business strategy. Additionally, the community is linked to Amazon.com, a company founded in 1993 by Jeff Benzos. Originally an online bookstore, Amazon has evolved into a vast retail enterprise valued at $48 billion, offering a wide range of products across more than forty categories. The company saw substantial growth during the Dot-Com Bubble, with Jeff Benzos playing a crucial role in its expansion and success. This connection to Amazon may indicate that the course or group discussions could involve case studies or strategic analyses of Amazon's business model and growth trajectory.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offers a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, regulated by the Federal Trade Commission, and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offer a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, regulated by the Federal Trade Commission, and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offers a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, being regulated by the Federal Trade Commission and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nThe community consists of individuals and entities connected through educational and business endeavors. Jin Can Chen, Jae Kim, Jessica Zhang, John Chen, and Tristan Landrecht are all participants in Bus 478, a seminar focused on business strategy, which emphasizes teamwork and collaboration. This educational setting likely fosters skills relevant to business growth and strategy, akin to those demonstrated by Amazon.com. Founded in 1993 by Jeff Benzos, Amazon began as an online bookstore and evolved into a vast retail empire valued at $48 billion, offering a diverse range of products across more than forty categories. The company's significant expansion, particularly during the Dot-Com Bubble, highlights the importance of strategic business planning and leadership, as exemplified by Benzos' pivotal role in its success. This connection between the educational focus of Bus 478 and the business strategies employed by Amazon underscores the relevance of strategic thinking in both academic and real-world business contexts.\n----\nThe community consists of individuals and entities connected through educational and business endeavors. Jin Can Chen, Jae Kim, Jessica Zhang, John Chen, and Tristan Landrecht are all participants in Bus 478, a seminar focused on business strategy, which emphasizes teamwork and collaboration. This educational setting likely fosters skills relevant to business growth and strategy, akin to those demonstrated by Amazon.com. Founded in 1993 by Jeff Benzos, Amazon began as an online bookstore and evolved into a vast retail empire valued at $48 billion, offering a diverse range of products across more than forty categories. The company's significant expansion, particularly during the Dot-Com Bubble, highlights the importance of strategic business planning and leadership, as exemplified by Benzos' pivotal role in its success. This connection between the educational focus of Bus 478 and the business strategies employed by Amazon underscores the relevance of strategic thinking in both academic and real-world business contexts.\n----\nAmazon.com, founded in 1993 by Jeff Benzos, initially started as an online bookstore. Over the years, it has grown into a massive retail enterprise valued at $48 billion, offering products across more than forty categories. The company experienced significant growth momentum during the Dot-Com Bubble. Jeff Benzos, the founder, played a pivotal role in its development and expansion.\n----\nT. Albert is associated with Maaillustrations.Com, an organization, through an illustrative collaboration.\n----\nJin Can Chen, Jae Kim, Jessica Zhang, John Chen, and Tristan Landrecht are all members of the course Bus 478, which is a seminar on business strategy. They are part of a group within this course, indicating a collaborative or team-based component to the class.\nDocument end\n""]","The context does not provide specific information on how Amazon's M&A strategy, transitioning from an online bookstore to a multi-category platform, has been shaped by competition.",multi_context,0.0,1.0,0.5384615384615384,0.9379910810877466,0.9091835548929823 +What strategies are Amazon's book competitors using for market share and how does it compare to Amazon's?,vector,"Amazon's book competitors, such as Barnes and Noble, employ an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by offering books not readily available at a lower price. They aim to increase profitability, gain market share, and provide a wide variety of products through competitive pricing, cost leadership, and differentiation strategies. In comparison, Amazon utilizes a broad corporate-level strategy that includes mergers and acquisitions, transforming into a one-stop online retail destination. Amazon focuses on low prices, convenience, selection, and availability, leveraging technological progress to cater to a wide range of products beyond books.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: \t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: \t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \nDocument end\n']","Amazon's book competitors are pursuing an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. They aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. They believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. They offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. On the other hand, Amazon uses a huge amount of data storage to improve customer service and is planning to reduce investments in the Kindle and Cloud initiatives next year. They are also interested in long-term investments, such as video content and distribution centers.",multi_context,0.9999999999,0.7142857142857143,0.9375,0.9328662796416046,0.7306795185463123 +What strategies are Amazon's book competitors using for market share and how does it compare to Amazon's?,fulltext,"Amazon's book competitors, such as Barnes and Noble, employ an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by offering books not readily available at a lower price. They aim to increase profitability, gain market share, and provide a wide variety of products through competitive pricing, cost leadership, and differentiation strategies. In comparison, Amazon focuses on a broader market strategy, aiming to be a one-stop-shop for all online purchases, not just limited to books. Amazon's competitive advantage lies in its vast selection, convenience, and customer service quality rather than just pricing or product differentiation in the book industry.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: \t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: \t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\nDocument end\n']","Amazon's book competitors are pursuing an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. They aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. They believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. They offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. On the other hand, Amazon uses a huge amount of data storage to improve customer service and is planning to reduce investments in the Kindle and Cloud initiatives next year. They are also interested in long-term investments, such as video content and distribution centers.",multi_context,0.9999999999,0.7142857142857143,0.9285714285714286,0.9328848633149723,0.7158051886779939 +What strategies are Amazon's book competitors using for market share and how does it compare to Amazon's?,entity search+vector,"Amazon's book competitors, like Barnes and Noble and eBay, employ various strategies to compete for market share. Barnes and Noble focuses on physical retail stores, offering a personalized in-store experience and a wide selection of books. On the other hand, eBay emphasizes its online marketplace model, enabling individuals to buy and sell books directly. + +In comparison to Amazon, Barnes and Noble and eBay face challenges due to Amazon's extensive product range, competitive pricing, and efficient online platform. Amazon's ability to offer a vast selection of books, competitive prices, and convenient shopping experience has positioned it as a dominant force in the market, making it challenging for competitors to match its scale and customer reach.","[""Document start\nThis Document belongs to the source unknown\nContent: chunks:\n- \t\r \xa0 3 online payment methods such as online banking and PayPal create more convenience in purchase transactions, which in turn enhances customers’ online shopping experience. Also, the invention of electronic devices such as smartphones deliver easy and convenient transaction processes, further facilitating online shopping. For instance, Amazon recently released a smartphone app for their Kindle services, allowing users to conveniently access the online sales platform and review products before purchasing. In the future, the use of 3D virtual technology to market products will also take online shopping to new heights. Political/Legal In the modern day environment, firms must be cautious when they deal with international policies on online distribution. In the U.S., electronic commerce firms are regulated by the Federal Trade Commission, which regulates online advertising and the security of consumers’ personal information. On the other hand, International Consumer Protection and Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions \n- Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers. Demographic As the world’s population is aging rapidly, baby boomers are moving towards retirement so that they will have weaker purchasing power. Thus, generation X and Y have become companies’ target markets for product selling. These generations are technologically adept and tend to engage more in online purchasing. Based on a survey, 62 percent of Generation Y liked to purchase things online, as compared to 32 percent of those aged older than 50. Organizations \n- providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \ncommunities:\n- Neo4j is a comprehensive graph database management system that offers a wide range of products, services, and resources to support graph data science and related applications. It provides various deployment options, including Cloud Managed Services, Self-Hosted, and Graph-As-A-Service, with Amazon AWS as a cloud provider. Neo4j's offerings include the Neo4j Graph Data Science product, Neo4j GraphQL Library, Neo4j Workspace, Neo4j Bloom visualization tool, Neo4j Developer Tools, and Neo4j Data Connectors, all of which are integral parts of the Neo4j ecosystem.\n\nThe organization supports learning and development through resources like Graphacademy, which offers free online courses and certifications, and the Neo4j Blog for daily insights. It also provides a Resource Library with white papers and data sheets, Case Studies showcasing customer success stories, and Executive Insights on graph technology.\n\nNeo4j hosts various events, including the Neo4j Events Hub for live and on-demand training, webinars, and demos, the quarterly online conference Connections, and the global Graphsummit tour. The Cypher query language is a key technology used within Neo4j for exploring and manipulating graph data.\n\nAdditionally, Neo4j includes a company structure with information about its culture, diversity, leadership, and partnerships, offering opportunities to find or become a partner through its Partner Portal.\n- Amazon.com, founded in 1993 by Jeff Benzos, initially started as an online bookstore. Over the years, it has grown into a massive retail enterprise valued at $48 billion, offering products across more than forty categories. The company experienced significant growth momentum during the Dot-Com Bubble. Jeff Benzos, the founder, played a pivotal role in its development and expansion.\n- Amazon is a rapidly growing multinational e-commerce retailer based in America with a significant international presence. It faces competition from major organizations such as eBay, Barnes and Noble, and Wal-Mart. eBay and Barnes and Noble are noted for their product breadth and geographic market coverage, while Wal-Mart is recognized as the world's largest retail chain, employing a cost leadership strategy.\n\nAmazon competes with eBay, which utilizes both cost leadership and differentiation strategies. Barnes and Noble also competes with Amazon, employing an integrated focused cost leadership/differentiation strategy. Wal-Mart, another competitor, uses a cost leadership approach.\n\nAmazon is actively investing in various technologies and products, including video content, cloud services, and its Kindle product. It utilizes technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations. The company has also released a smartphone app and is located at the U.S. East Data Center.\n\nAmazon sees opportunities in emerging markets like China, which has a large population and growing disposable income. It is focused on capturing the global market and has invested in distribution centers to support this goal. The company discloses information about online sales taxes and is regulated by the Federal Trade Commission. Additionally, it receives support from the International Consumer Protection and Enforcement Network.\nentities:\n- Company:Amazon.Com Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.\n- Organization:Amazon Fastest-growing, multinational e-commerce retailer in America with international presence.\n- Company:Amazon Aws \n- Organization:Barnes And Noble Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.\n- Organization:Amazon Cooperation Treaty Organization \n- Concept:Bargaining_Power_Of_Buyers High because customers can choose among numerous online stores for the lowest price.\n- Concept:E-Commerce \n- Electronic_Commerce_Firms \n- Concept:Bargaining_Power_Of_Suppliers Low due to the substantial number of suppliers and the vast online global distribution network.\n- Group:Consumers \nrelationships:\n- Amazon COMPETITOR Barnes And Noble\n- Amazon COMPETES_WITH Barnes And Noble\n- Barnes And Noble COMPETES_WITH Amazon\noutside:\n nodes:\n - Activity:Online Shopping \n - Organization:Ebay Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.\n - Organization:Wal-Mart World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.\n - Date:1993 \n - Person:Jeff Benzos Founder of Amazon.com\n - Organization:International Consumer Protection And Enforcement Network \n - Organization:Federal Trade Commission \n - Course:Bus 478 Seminar on Business Strategy\n - Country:India Emerging country with large population and growing disposable income.\n - Event:Dot-Com Bubble \n relationships:\n - Organization:Amazon BENEFIT Activity:Online Shopping\n - Concept:E-Commerce ENABLES Activity:Online Shopping\n - Group:Consumers PREFERENCE Activity:Online Shopping\n - Organization:Amazon COMPETITOR Organization:Ebay\n - Organization:Ebay COMPETES_WITH Organization:Amazon\n - Organization:Amazon COMPETES_WITH Organization:Ebay\n - Organization:Amazon COMPETITOR Organization:Wal-Mart\n - Organization:Amazon COMPETES_WITH Organization:Wal-Mart\n - Company:Amazon.Com FOUNDED Date:1993\n - Company:Amazon.Com FOUNDER Person:Jeff Benzos\n - Organization:International Consumer Protection And Enforcement Network SUPPORTS Organization:Amazon\n - Organization:Federal Trade Commission REGULATES Organization:Amazon\n - Course:Bus 478 PROJECT Company:Amazon.Com\n - Organization:Amazon OPPORTUNITY Country:India\n - Company:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\n\nDocument end\n""]","Amazon's book competitors are pursuing an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. They aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. They believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. They offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. On the other hand, Amazon uses a huge amount of data storage to improve customer service and is planning to reduce investments in the Kindle and Cloud initiatives next year. They are also interested in long-term investments, such as video content and distribution centers.",multi_context,0.9999999999,0.14285714285714285,0.4375,0.9700955094824905,0.6921551328857438 +What strategies are Amazon's book competitors using for market share and how does it compare to Amazon's?,graph+vector,"Amazon's book competitors, such as eBay and Barnes and Noble, employ various strategies to compete for market share. eBay focuses on cost leadership by operating as an online auction house without physical inventories, while also offering a wide range of products and high-quality services. Barnes and Noble, on the other hand, utilizes an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing unique books at competitive prices. + +In comparison to Amazon, these competitors aim to increase profitability, gain market share, and offer a variety of products through competitive pricing, cost leadership, and differentiation strategies. While Amazon has a strong presence in the market due to its technological advancements, broad product categories, and global reach, its competitors like eBay and Barnes and Noble focus on specific niches and strategies to carve out their market share in the book industry.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: Text Content:\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Shivam Dube PLAYER Country:India\n\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: Text Content:\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Shivam Dube PLAYER Country:India\n\nDocument end\n']","Amazon's book competitors are pursuing an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. They aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. They believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. They offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. On the other hand, Amazon uses a huge amount of data storage to improve customer service and is planning to reduce investments in the Kindle and Cloud initiatives next year. They are also interested in long-term investments, such as video content and distribution centers.",multi_context,0.9999999999,0.7142857142857143,1.0,0.9579425934098755,0.49139780263611665 +What strategies are Amazon's book competitors using for market share and how does it compare to Amazon's?,graph+vector+fulltext,"Amazon's book competitors, such as eBay and Barnes and Noble, employ various strategies to compete for market share. eBay focuses on cost leadership by operating as an online auction house without physical inventory, while also offering a wide range of products and high-quality services. Barnes and Noble, on the other hand, utilizes an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing unique books at competitive prices. + +In comparison to Amazon, these competitors aim to increase profitability, gain market share, and offer a variety of products through competitive pricing, cost leadership, and differentiation strategies. While Amazon has a strong online presence and a diverse product range, its competitors like eBay and Barnes and Noble focus on specific niches and unique offerings to attract customers. Amazon's competitive advantage lies in its technological innovations, customer service quality, and convenience, while its competitors differentiate themselves through targeted strategies and product offerings.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: Text Content:\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Shivam Dube PLAYER Country:India\n\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: Text Content:\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Shivam Dube PLAYER Country:India\n\nDocument end\n']","Amazon's book competitors are pursuing an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. They aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. They believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. They offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. On the other hand, Amazon uses a huge amount of data storage to improve customer service and is planning to reduce investments in the Kindle and Cloud initiatives next year. They are also interested in long-term investments, such as video content and distribution centers.",multi_context,0.9999999999,0.7142857142857143,1.0,0.9523668132157023,0.44704411382876297 +What strategies are Amazon's book competitors using for market share and how does it compare to Amazon's?,global search+vector+fulltext,"Amazon's book competitors employ various strategies to compete for market share. eBay utilizes both cost leadership and differentiation strategies, aiming to offer competitive pricing and a unique value proposition to customers. Barnes and Noble integrates a focused cost leadership/differentiation strategy, focusing on specific market segments while offering differentiated products and services. Wal-Mart, as the world's largest retail chain, primarily focuses on a cost leadership approach, leveraging its scale to provide competitive prices. + +In comparison, Amazon employs a mix of strategies, heavily investing in technologies like video content, cloud services, and its Kindle product. It leverages technologies such as Elastic Block Storage (EBS) and 1-Click Ordering to enhance operations and customer experience. Amazon's strategic focus on innovation, technology, and global market expansion sets it apart from its competitors, allowing it to maintain a strong position in the e-commerce landscape.","[""Document start\nThis Document belongs to the source unknown\nContent: Amazon is a rapidly growing multinational e-commerce retailer based in America with a significant international presence. It faces competition from major organizations such as eBay, Barnes and Noble, and Wal-Mart. eBay and Barnes and Noble are noted for their product breadth and geographic market coverage, while Wal-Mart is recognized as the world's largest retail chain, employing a cost leadership strategy.\n\nAmazon competes with eBay, which utilizes both cost leadership and differentiation strategies. Barnes and Noble also competes with Amazon, employing an integrated focused cost leadership/differentiation strategy. Wal-Mart, another competitor, uses a cost leadership approach.\n\nAmazon is actively investing in various technologies and products, including video content, cloud services, and its Kindle product. It utilizes technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations. The company has also released a smartphone app and is located at the U.S. East Data Center.\n\nAmazon sees opportunities in emerging markets like China, which has a large population and growing disposable income. It is focused on capturing the global market and has invested in distribution centers to support this goal. The company discloses information about online sales taxes and is regulated by the Federal Trade Commission. Additionally, it receives support from the International Consumer Protection and Enforcement Network.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offers a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, regulated by the Federal Trade Commission, and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offer a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, regulated by the Federal Trade Commission, and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offers a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, being regulated by the Federal Trade Commission and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nAmazon.com, founded in 1993 by Jeff Benzos, initially started as an online bookstore. Over the years, it has grown into a massive retail enterprise valued at $48 billion, offering products across more than forty categories. The company experienced significant growth momentum during the Dot-Com Bubble. Jeff Benzos, the founder, played a pivotal role in its development and expansion.\n----\nThe community consists of a group of individuals, Jin Can Chen, Jae Kim, Jessica Zhang, John Chen, and Tristan Landrecht, who are enrolled in Bus 478, a seminar focused on business strategy. This course involves a collaborative or team-based approach, suggesting that these members work closely together on projects or discussions related to business strategy. Additionally, the community is linked to Amazon.com, a company founded in 1993 by Jeff Benzos. Originally an online bookstore, Amazon has evolved into a vast retail enterprise valued at $48 billion, offering a wide range of products across more than forty categories. The company saw substantial growth during the Dot-Com Bubble, with Jeff Benzos playing a crucial role in its expansion and success. This connection to Amazon may indicate that the course or group discussions could involve case studies or strategic analyses of Amazon's business model and growth trajectory.\n----\nThe community consists of individuals and entities connected through educational and business endeavors. Jin Can Chen, Jae Kim, Jessica Zhang, John Chen, and Tristan Landrecht are all participants in Bus 478, a seminar focused on business strategy, which emphasizes teamwork and collaboration. This educational setting likely fosters skills relevant to business growth and strategy, akin to those demonstrated by Amazon.com. Founded in 1993 by Jeff Benzos, Amazon began as an online bookstore and evolved into a vast retail empire valued at $48 billion, offering a diverse range of products across more than forty categories. The company's significant expansion, particularly during the Dot-Com Bubble, highlights the importance of strategic business planning and leadership, as exemplified by Benzos' pivotal role in its success. This connection between the educational focus of Bus 478 and the business strategies employed by Amazon underscores the relevance of strategic thinking in both academic and real-world business contexts.\n----\nThe community consists of individuals and entities connected through educational and business endeavors. Jin Can Chen, Jae Kim, Jessica Zhang, John Chen, and Tristan Landrecht are all participants in Bus 478, a seminar focused on business strategy, which emphasizes teamwork and collaboration. This educational setting likely fosters skills relevant to business growth and strategy, akin to those demonstrated by Amazon.com. Founded in 1993 by Jeff Benzos, Amazon began as an online bookstore and evolved into a vast retail empire valued at $48 billion, offering a diverse range of products across more than forty categories. The company's significant expansion, particularly during the Dot-Com Bubble, highlights the importance of strategic business planning and leadership, as exemplified by Benzos' pivotal role in its success. This connection between the educational focus of Bus 478 and the business strategies employed by Amazon underscores the relevance of strategic thinking in both academic and real-world business contexts.\n----\nThe online shopping landscape is undergoing a transformative enhancement through the integration of 3D virtual technology, which aims to significantly elevate the consumer experience. This technological advancement is complemented by the widespread use of electronic devices, particularly smartphones, which are streamlining and simplifying transaction processes for online shoppers. Furthermore, emerging markets, notably China and India, are poised to play a pivotal role in the expansion of online shopping. These countries, characterized by their vast populations and rising disposable incomes, offer substantial opportunities for growth and development in the online retail sector.\n----\nThe online shopping landscape is undergoing a transformative enhancement through the integration of 3D virtual technology, which aims to significantly elevate the consumer experience. This technological advancement is complemented by the widespread use of electronic devices, particularly smartphones, which are streamlining and simplifying transaction processes for online shoppers. Furthermore, emerging markets, notably China and India, are poised to play a pivotal role in the expansion of online shopping. These countries, characterized by their vast populations and rising disposable incomes, offer substantial opportunities for growth and development in the online retail sector.\nDocument end\n""]","Amazon's book competitors are pursuing an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. They aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. They believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. They offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. On the other hand, Amazon uses a huge amount of data storage to improve customer service and is planning to reduce investments in the Kindle and Cloud initiatives next year. They are also interested in long-term investments, such as video content and distribution centers.",multi_context,0.9999999999,0.14285714285714285,0.45454545454545453,0.9568093643875176,0.6372330251599038 +What methods does ICPEN use for cross-border online consumer issues and its effect on retailers like Amazon?,vector,"ICPEN, the International Consumer Protection and Enforcement Network, addresses cross-border online consumer issues by finding ways to tackle problems in both goods and services transactions. This helps ensure fair benefits and mutual understanding among participants. For retailers like Amazon, it emphasizes the importance of disclosing online sales taxes accurately when advertising products internationally to avoid customer confusion due to varying tax rates in different countries.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: \t\r \xa0 3 online payment methods such as online banking and PayPal create more convenience in purchase transactions, which in turn enhances customers’ online shopping experience. Also, the invention of electronic devices such as smartphones deliver easy and convenient transaction processes, further facilitating online shopping. For instance, Amazon recently released a smartphone app for their Kindle services, allowing users to conveniently access the online sales platform and review products before purchasing. In the future, the use of 3D virtual technology to market products will also take online shopping to new heights. Political/Legal In the modern day environment, firms must be cautious when they deal with international policies on online distribution. In the U.S., electronic commerce firms are regulated by the Federal Trade Commission, which regulates online advertising and the security of consumers’ personal information. On the other hand, International Consumer Protection and Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions \n----\n Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers. Demographic As the world’s population is aging rapidly, baby boomers are moving towards retirement so that they will have weaker purchasing power. Thus, generation X and Y have become companies’ target markets for product selling. These generations are technologically adept and tend to engage more in online purchasing. Based on a survey, 62 percent of Generation Y liked to purchase things online, as compared to 32 percent of those aged older than 50. Organizations \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: \t\r \xa0 3 online payment methods such as online banking and PayPal create more convenience in purchase transactions, which in turn enhances customers’ online shopping experience. Also, the invention of electronic devices such as smartphones deliver easy and convenient transaction processes, further facilitating online shopping. For instance, Amazon recently released a smartphone app for their Kindle services, allowing users to conveniently access the online sales platform and review products before purchasing. In the future, the use of 3D virtual technology to market products will also take online shopping to new heights. Political/Legal In the modern day environment, firms must be cautious when they deal with international policies on online distribution. In the U.S., electronic commerce firms are regulated by the Federal Trade Commission, which regulates online advertising and the security of consumers’ personal information. On the other hand, International Consumer Protection and Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions \n----\n Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers. Demographic As the world’s population is aging rapidly, baby boomers are moving towards retirement so that they will have weaker purchasing power. Thus, generation X and Y have become companies’ target markets for product selling. These generations are technologically adept and tend to engage more in online purchasing. Based on a survey, 62 percent of Generation Y liked to purchase things online, as compared to 32 percent of those aged older than 50. Organizations \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\nDocument end\n']",ICPEN finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers.,multi_context,0.9999999999,1.0,1.0,0.944883789738359,0.991201905586986 +What methods does ICPEN use for cross-border online consumer issues and its effect on retailers like Amazon?,fulltext,"ICPEN, the International Consumer Protection and Enforcement Network, addresses cross-border online consumer issues by finding ways to tackle problems involving transactions in both goods and services. This helps ensure fair benefits and mutual understanding among participants. For retailers like Amazon, it emphasizes the importance of disclosing online sales taxes accurately when advertising products internationally to avoid customer confusion. This transparency is crucial as different sales tax regulations can impact customer trust and satisfaction, especially in the context of online shopping platforms.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: \t\r \xa0 3 online payment methods such as online banking and PayPal create more convenience in purchase transactions, which in turn enhances customers’ online shopping experience. Also, the invention of electronic devices such as smartphones deliver easy and convenient transaction processes, further facilitating online shopping. For instance, Amazon recently released a smartphone app for their Kindle services, allowing users to conveniently access the online sales platform and review products before purchasing. In the future, the use of 3D virtual technology to market products will also take online shopping to new heights. Political/Legal In the modern day environment, firms must be cautious when they deal with international policies on online distribution. In the U.S., electronic commerce firms are regulated by the Federal Trade Commission, which regulates online advertising and the security of consumers’ personal information. On the other hand, International Consumer Protection and Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions \n----\n Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers. Demographic As the world’s population is aging rapidly, baby boomers are moving towards retirement so that they will have weaker purchasing power. Thus, generation X and Y have become companies’ target markets for product selling. These generations are technologically adept and tend to engage more in online purchasing. Based on a survey, 62 percent of Generation Y liked to purchase things online, as compared to 32 percent of those aged older than 50. Organizations \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: \t\r \xa0 3 online payment methods such as online banking and PayPal create more convenience in purchase transactions, which in turn enhances customers’ online shopping experience. Also, the invention of electronic devices such as smartphones deliver easy and convenient transaction processes, further facilitating online shopping. For instance, Amazon recently released a smartphone app for their Kindle services, allowing users to conveniently access the online sales platform and review products before purchasing. In the future, the use of 3D virtual technology to market products will also take online shopping to new heights. Political/Legal In the modern day environment, firms must be cautious when they deal with international policies on online distribution. In the U.S., electronic commerce firms are regulated by the Federal Trade Commission, which regulates online advertising and the security of consumers’ personal information. On the other hand, International Consumer Protection and Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions \n----\n Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers. Demographic As the world’s population is aging rapidly, baby boomers are moving towards retirement so that they will have weaker purchasing power. Thus, generation X and Y have become companies’ target markets for product selling. These generations are technologically adept and tend to engage more in online purchasing. Based on a survey, 62 percent of Generation Y liked to purchase things online, as compared to 32 percent of those aged older than 50. Organizations \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\nDocument end\n']",ICPEN finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers.,multi_context,0.9999999999,1.0,0.6666666666666666,0.9448215167722637,0.9928426564003855 +What methods does ICPEN use for cross-border online consumer issues and its effect on retailers like Amazon?,entity search+vector,"ICPEN, the International Consumer Protection and Enforcement Network, addresses cross-border transactions to tackle consumer problems involving goods and services. By doing so, it ensures that participants equally benefit and reach mutual understanding. For retailers like Amazon, this means they need to be cautious about disclosing online sales taxes when advertising products internationally to avoid customer confusion due to varying tax rates. This transparency is crucial for maintaining consumer trust and compliance with international regulations.","[""Document start\nThis Document belongs to the source unknown\nContent: chunks:\n- \t\r \xa0 3 online payment methods such as online banking and PayPal create more convenience in purchase transactions, which in turn enhances customers’ online shopping experience. Also, the invention of electronic devices such as smartphones deliver easy and convenient transaction processes, further facilitating online shopping. For instance, Amazon recently released a smartphone app for their Kindle services, allowing users to conveniently access the online sales platform and review products before purchasing. In the future, the use of 3D virtual technology to market products will also take online shopping to new heights. Political/Legal In the modern day environment, firms must be cautious when they deal with international policies on online distribution. In the U.S., electronic commerce firms are regulated by the Federal Trade Commission, which regulates online advertising and the security of consumers’ personal information. On the other hand, International Consumer Protection and Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions \n- Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers. Demographic As the world’s population is aging rapidly, baby boomers are moving towards retirement so that they will have weaker purchasing power. Thus, generation X and Y have become companies’ target markets for product selling. These generations are technologically adept and tend to engage more in online purchasing. Based on a survey, 62 percent of Generation Y liked to purchase things online, as compared to 32 percent of those aged older than 50. Organizations \n- \t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\ncommunities:\n- Neo4j is a comprehensive graph database management system that offers a wide range of products, services, and resources to support graph data science and related applications. It provides various deployment options, including Cloud Managed Services, Self-Hosted, and Graph-As-A-Service, with Amazon AWS as a cloud provider. Neo4j's offerings include the Neo4j Graph Data Science product, Neo4j GraphQL Library, Neo4j Workspace, Neo4j Bloom visualization tool, Neo4j Developer Tools, and Neo4j Data Connectors, all of which are integral parts of the Neo4j ecosystem.\n\nThe organization supports learning and development through resources like Graphacademy, which offers free online courses and certifications, and the Neo4j Blog for daily insights. It also provides a Resource Library with white papers and data sheets, Case Studies showcasing customer success stories, and Executive Insights on graph technology.\n\nNeo4j hosts various events, including the Neo4j Events Hub for live and on-demand training, webinars, and demos, the quarterly online conference Connections, and the global Graphsummit tour. The Cypher query language is a key technology used within Neo4j for exploring and manipulating graph data.\n\nAdditionally, Neo4j includes a company structure with information about its culture, diversity, leadership, and partnerships, offering opportunities to find or become a partner through its Partner Portal.\n- Amazon is a rapidly growing multinational e-commerce retailer based in America with a significant international presence. It faces competition from major organizations such as eBay, Barnes and Noble, and Wal-Mart. eBay and Barnes and Noble are noted for their product breadth and geographic market coverage, while Wal-Mart is recognized as the world's largest retail chain, employing a cost leadership strategy.\n\nAmazon competes with eBay, which utilizes both cost leadership and differentiation strategies. Barnes and Noble also competes with Amazon, employing an integrated focused cost leadership/differentiation strategy. Wal-Mart, another competitor, uses a cost leadership approach.\n\nAmazon is actively investing in various technologies and products, including video content, cloud services, and its Kindle product. It utilizes technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations. The company has also released a smartphone app and is located at the U.S. East Data Center.\n\nAmazon sees opportunities in emerging markets like China, which has a large population and growing disposable income. It is focused on capturing the global market and has invested in distribution centers to support this goal. The company discloses information about online sales taxes and is regulated by the Federal Trade Commission. Additionally, it receives support from the International Consumer Protection and Enforcement Network.\n- Amazon is a rapidly growing multinational e-commerce retailer based in America with a significant international presence. It faces competition from major organizations such as eBay, Barnes and Noble, and Wal-Mart. eBay and Barnes and Noble are noted for their product breadth and geographic market coverage, while Wal-Mart is recognized as the world's largest retail chain, employing a cost leadership strategy.\n\nAmazon competes with eBay, which utilizes both cost leadership and differentiation strategies. Barnes and Noble also competes with Amazon, employing an integrated focused cost leadership/differentiation strategy. Wal-Mart, another competitor, uses a cost leadership approach.\n\nAmazon is actively investing in various technologies and products, including video content, cloud services, and its Kindle product. It utilizes technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations. The company has also released a smartphone app and is located at the U.S. East Data Center.\n\nAmazon sees opportunities in emerging markets like China, which has a large population and growing disposable income. It is focused on capturing the global market and has invested in distribution centers to support this goal. The company discloses information about online sales taxes and is regulated by the Federal Trade Commission. Additionally, it receives support from the International Consumer Protection and Enforcement Network.\nentities:\n- Organization:Icpen Finds ways to tackle consumer problems involving cross-border transactions.\n- Online_Purchasing \n- Concept:E-Commerce \n- Online_Shopping \n- Activity:Online Shopping \n- Organization:Amazon Fastest-growing, multinational e-commerce retailer in America with international presence.\n- Organization:International Consumer Protection And Enforcement Network \n- Concept:Bargaining_Power_Of_Buyers High because customers can choose among numerous online stores for the lowest price.\n- Company:Amazon Aws \n- Online_Shopping_Experience \nrelationships:\n- E-Commerce ENABLES Online Shopping\n- Amazon BENEFIT Online Shopping\n- International Consumer Protection And Enforcement Network SUPPORTS Amazon\noutside:\n nodes:\n - Organization:Ebay Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.\n - Organization:Barnes And Noble Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.\n - Organization:Wal-Mart World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.\n - Location:China_And_India Emerging countries with large populations and growing disposable income.\n - Concept:Modern Tech Support \n - Concept:Web Security \n - Concept:3D_Virtual_Technology Technology that will take online shopping to new heights.\n - Group:Baby Boomers \n - Technology:3D Virtual Technology \n - Group:Consumers \n relationships:\n - Organization:Amazon COMPETITOR Organization:Ebay\n - Organization:Ebay COMPETES_WITH Organization:Amazon\n - Organization:Amazon COMPETES_WITH Organization:Ebay\n - Organization:Amazon COMPETITOR Organization:Barnes And Noble\n - Organization:Barnes And Noble COMPETES_WITH Organization:Amazon\n - Organization:Amazon COMPETES_WITH Organization:Barnes And Noble\n - Organization:Amazon COMPETITOR Organization:Wal-Mart\n - Organization:Amazon COMPETES_WITH Organization:Wal-Mart\n - Location:China_And_India OPPORTUNITY_FOR Online_Shopping\n - Concept:Modern Tech Support FACILITATES Activity:Online Shopping\n - Concept:Web Security FACILITATES Activity:Online Shopping\n - Concept:3D_Virtual_Technology ENHANCES Online_Shopping\n - Group:Baby Boomers LESS_INVOLVED Activity:Online Shopping\n - Technology:3D Virtual Technology FUTURE Activity:Online Shopping\n - Group:Consumers PREFERENCE Activity:Online Shopping\n\nDocument end\n""]",ICPEN finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers.,multi_context,0.9999999999,0.6666666666666666,0.8,0.8978613181525779,0.9922690115395673 +What methods does ICPEN use for cross-border online consumer issues and its effect on retailers like Amazon?,graph+vector,"ICPEN, the International Consumer Protection and Enforcement Network, addresses cross-border transactions by finding ways to tackle consumer problems involving such transactions in both goods and services. This helps ensure that participants equally benefit and reach mutual understanding. For retailers like Amazon, this means they need to be cautious about disclosing online sales taxes when advertising products to other countries via online shopping platforms to avoid customer confusion. By adhering to these regulations, online retailers can maintain transparency and trust with their international customers.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: Text Content:\n\t\r \xa0 3 online payment methods such as online banking and PayPal create more convenience in purchase transactions, which in turn enhances customers’ online shopping experience. Also, the invention of electronic devices such as smartphones deliver easy and convenient transaction processes, further facilitating online shopping. For instance, Amazon recently released a smartphone app for their Kindle services, allowing users to conveniently access the online sales platform and review products before purchasing. In the future, the use of 3D virtual technology to market products will also take online shopping to new heights. Political/Legal In the modern day environment, firms must be cautious when they deal with international policies on online distribution. In the U.S., electronic commerce firms are regulated by the Federal Trade Commission, which regulates online advertising and the security of consumers’ personal information. On the other hand, International Consumer Protection and Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions \n----\n Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers. Demographic As the world’s population is aging rapidly, baby boomers are moving towards retirement so that they will have weaker purchasing power. Thus, generation X and Y have become companies’ target markets for product selling. These generations are technologically adept and tend to engage more in online purchasing. Based on a survey, 62 percent of Generation Y liked to purchase things online, as compared to 32 percent of those aged older than 50. Organizations \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\nEntities:\n:Cost Leadership\n:Cross-Border_Transactions\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Online_Shopping\n:Online_Shopping_Experience\n:Smartphone_App\nActivity:Online Shopping\nConcept:3D_Virtual_Technology (Technology that will take online shopping to new heights.)\nConcept:Bargaining_Power_Of_Buyers (High because customers can choose among numerous online stores for the lowest price.)\nConcept:Bargaining_Power_Of_Suppliers (Low due to the substantial number of suppliers and the vast online global distribution network.)\nConcept:E-Commerce\nConcept:Electronic_Devices (Devices such as smartphones that deliver easy and convenient transaction processes.)\nConcept:Modern Tech Support\nConcept:Online_Payment_Methods (Methods such as online banking and PayPal that create convenience in purchase transactions.)\nConcept:Threat_Of_New_Entrants (Considered low due to low capital investment costs but high infrastructure and inventory requirements.)\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nGroup:Baby Boomers\nGroup:Consumers\nGroup:Generation X\nGroup:Generation Y\nLocation:China_And_India (Emerging countries with large populations and growing disposable income.)\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nMarket:Emerging Markets\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Icpen (Finds ways to tackle consumer problems involving cross-border transactions.)\nOrganization:International Consumer Protection And Enforcement Network\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nProduct:Kindle\nTechnology:1-Click Ordering\nTechnology:3D Virtual Technology\nTechnology:Internet\nTechnology:Online Payment Methods\nTechnology:Smartphones\n----\nRelationships:\nConcept:3D_Virtual_Technology ENHANCES :Online_Shopping\nConcept:E-Commerce ENABLES Activity:Online Shopping\nConcept:Electronic_Devices FACILITATES :Online_Shopping\nConcept:Modern Tech Support FACILITATES Activity:Online Shopping\nConcept:Online_Payment_Methods ENHANCES :Online_Shopping_Experience\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nGroup:Baby Boomers LESS_INVOLVED Activity:Online Shopping\nGroup:Consumers PREFERENCE Activity:Online Shopping\nGroup:Generation X TARGET_MARKET Activity:Online Shopping\nGroup:Generation Y TARGET_MARKET Activity:Online Shopping\nLocation:China_And_India OPPORTUNITY_FOR :Online_Shopping\nMarket:Emerging Markets GROWTH Activity:Online Shopping\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Icpen ADDRESSES :Cross-Border_Transactions\nOrganization:International Consumer Protection And Enforcement Network SUPPORTS Organization:Amazon\nOrganization:Wal-Mart USES :Cost Leadership\nTechnology:3D Virtual Technology FUTURE Activity:Online Shopping\nTechnology:Internet SUPPORTS Activity:Online Shopping\nTechnology:Online Payment Methods ENHANCES Activity:Online Shopping\nTechnology:Smartphones FACILITATES Activity:Online Shopping\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: Text Content:\n\t\r \xa0 3 online payment methods such as online banking and PayPal create more convenience in purchase transactions, which in turn enhances customers’ online shopping experience. Also, the invention of electronic devices such as smartphones deliver easy and convenient transaction processes, further facilitating online shopping. For instance, Amazon recently released a smartphone app for their Kindle services, allowing users to conveniently access the online sales platform and review products before purchasing. In the future, the use of 3D virtual technology to market products will also take online shopping to new heights. Political/Legal In the modern day environment, firms must be cautious when they deal with international policies on online distribution. In the U.S., electronic commerce firms are regulated by the Federal Trade Commission, which regulates online advertising and the security of consumers’ personal information. On the other hand, International Consumer Protection and Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions \n----\n Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers. Demographic As the world’s population is aging rapidly, baby boomers are moving towards retirement so that they will have weaker purchasing power. Thus, generation X and Y have become companies’ target markets for product selling. These generations are technologically adept and tend to engage more in online purchasing. Based on a survey, 62 percent of Generation Y liked to purchase things online, as compared to 32 percent of those aged older than 50. Organizations \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\nEntities:\n:Cost Leadership\n:Cross-Border_Transactions\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Online_Shopping\n:Online_Shopping_Experience\n:Smartphone_App\nActivity:Online Shopping\nConcept:3D_Virtual_Technology (Technology that will take online shopping to new heights.)\nConcept:Bargaining_Power_Of_Buyers (High because customers can choose among numerous online stores for the lowest price.)\nConcept:Bargaining_Power_Of_Suppliers (Low due to the substantial number of suppliers and the vast online global distribution network.)\nConcept:E-Commerce\nConcept:Electronic_Devices (Devices such as smartphones that deliver easy and convenient transaction processes.)\nConcept:Modern Tech Support\nConcept:Online_Payment_Methods (Methods such as online banking and PayPal that create convenience in purchase transactions.)\nConcept:Threat_Of_New_Entrants (Considered low due to low capital investment costs but high infrastructure and inventory requirements.)\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nGroup:Baby Boomers\nGroup:Consumers\nGroup:Generation X\nGroup:Generation Y\nLocation:China_And_India (Emerging countries with large populations and growing disposable income.)\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nMarket:Emerging Markets\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Icpen (Finds ways to tackle consumer problems involving cross-border transactions.)\nOrganization:International Consumer Protection And Enforcement Network\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nProduct:Kindle\nTechnology:1-Click Ordering\nTechnology:3D Virtual Technology\nTechnology:Internet\nTechnology:Online Payment Methods\nTechnology:Smartphones\n----\nRelationships:\nConcept:3D_Virtual_Technology ENHANCES :Online_Shopping\nConcept:E-Commerce ENABLES Activity:Online Shopping\nConcept:Electronic_Devices FACILITATES :Online_Shopping\nConcept:Modern Tech Support FACILITATES Activity:Online Shopping\nConcept:Online_Payment_Methods ENHANCES :Online_Shopping_Experience\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nGroup:Baby Boomers LESS_INVOLVED Activity:Online Shopping\nGroup:Consumers PREFERENCE Activity:Online Shopping\nGroup:Generation X TARGET_MARKET Activity:Online Shopping\nGroup:Generation Y TARGET_MARKET Activity:Online Shopping\nLocation:China_And_India OPPORTUNITY_FOR :Online_Shopping\nMarket:Emerging Markets GROWTH Activity:Online Shopping\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Icpen ADDRESSES :Cross-Border_Transactions\nOrganization:International Consumer Protection And Enforcement Network SUPPORTS Organization:Amazon\nOrganization:Wal-Mart USES :Cost Leadership\nTechnology:3D Virtual Technology FUTURE Activity:Online Shopping\nTechnology:Internet SUPPORTS Activity:Online Shopping\nTechnology:Online Payment Methods ENHANCES Activity:Online Shopping\nTechnology:Smartphones FACILITATES Activity:Online Shopping\nDocument end\n']",ICPEN finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers.,multi_context,0.9999999999,1.0,1.0,0.8978613181525779,0.9181702852415992 +What methods does ICPEN use for cross-border online consumer issues and its effect on retailers like Amazon?,graph+vector+fulltext,"ICPEN, the International Consumer Protection and Enforcement Network, addresses cross-border transactions issues by finding ways to tackle consumer problems involving both goods and services. This helps ensure that participants equally benefit and reach mutual understanding. For retailers like Amazon, it emphasizes the importance of careful disclosure of online sales taxes when advertising products to other countries via online shopping platforms to avoid customer confusion. By addressing these cross-border consumer issues, ICPEN contributes to a more transparent and consumer-friendly online shopping environment, impacting retailers like Amazon by promoting fair practices and consumer trust.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: Text Content:\n\t\r \xa0 3 online payment methods such as online banking and PayPal create more convenience in purchase transactions, which in turn enhances customers’ online shopping experience. Also, the invention of electronic devices such as smartphones deliver easy and convenient transaction processes, further facilitating online shopping. For instance, Amazon recently released a smartphone app for their Kindle services, allowing users to conveniently access the online sales platform and review products before purchasing. In the future, the use of 3D virtual technology to market products will also take online shopping to new heights. Political/Legal In the modern day environment, firms must be cautious when they deal with international policies on online distribution. In the U.S., electronic commerce firms are regulated by the Federal Trade Commission, which regulates online advertising and the security of consumers’ personal information. On the other hand, International Consumer Protection and Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions \n----\n Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers. Demographic As the world’s population is aging rapidly, baby boomers are moving towards retirement so that they will have weaker purchasing power. Thus, generation X and Y have become companies’ target markets for product selling. These generations are technologically adept and tend to engage more in online purchasing. Based on a survey, 62 percent of Generation Y liked to purchase things online, as compared to 32 percent of those aged older than 50. Organizations \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\nEntities:\n:Cost Leadership\n:Cross-Border_Transactions\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Online_Shopping\n:Online_Shopping_Experience\n:Smartphone_App\nActivity:Online Shopping\nConcept:3D_Virtual_Technology (Technology that will take online shopping to new heights.)\nConcept:Bargaining_Power_Of_Buyers (High because customers can choose among numerous online stores for the lowest price.)\nConcept:Bargaining_Power_Of_Suppliers (Low due to the substantial number of suppliers and the vast online global distribution network.)\nConcept:E-Commerce\nConcept:Electronic_Devices (Devices such as smartphones that deliver easy and convenient transaction processes.)\nConcept:Modern Tech Support\nConcept:Online_Payment_Methods (Methods such as online banking and PayPal that create convenience in purchase transactions.)\nConcept:Threat_Of_New_Entrants (Considered low due to low capital investment costs but high infrastructure and inventory requirements.)\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nGroup:Baby Boomers\nGroup:Consumers\nGroup:Generation X\nGroup:Generation Y\nLocation:China_And_India (Emerging countries with large populations and growing disposable income.)\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nMarket:Emerging Markets\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Icpen (Finds ways to tackle consumer problems involving cross-border transactions.)\nOrganization:International Consumer Protection And Enforcement Network\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nProduct:Kindle\nTechnology:1-Click Ordering\nTechnology:3D Virtual Technology\nTechnology:Internet\nTechnology:Online Payment Methods\nTechnology:Smartphones\n----\nRelationships:\nConcept:3D_Virtual_Technology ENHANCES :Online_Shopping\nConcept:E-Commerce ENABLES Activity:Online Shopping\nConcept:Electronic_Devices FACILITATES :Online_Shopping\nConcept:Modern Tech Support FACILITATES Activity:Online Shopping\nConcept:Online_Payment_Methods ENHANCES :Online_Shopping_Experience\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nGroup:Baby Boomers LESS_INVOLVED Activity:Online Shopping\nGroup:Consumers PREFERENCE Activity:Online Shopping\nGroup:Generation X TARGET_MARKET Activity:Online Shopping\nGroup:Generation Y TARGET_MARKET Activity:Online Shopping\nLocation:China_And_India OPPORTUNITY_FOR :Online_Shopping\nMarket:Emerging Markets GROWTH Activity:Online Shopping\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Icpen ADDRESSES :Cross-Border_Transactions\nOrganization:International Consumer Protection And Enforcement Network SUPPORTS Organization:Amazon\nOrganization:Wal-Mart USES :Cost Leadership\nTechnology:3D Virtual Technology FUTURE Activity:Online Shopping\nTechnology:Internet SUPPORTS Activity:Online Shopping\nTechnology:Online Payment Methods ENHANCES Activity:Online Shopping\nTechnology:Smartphones FACILITATES Activity:Online Shopping\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: Text Content:\n\t\r \xa0 3 online payment methods such as online banking and PayPal create more convenience in purchase transactions, which in turn enhances customers’ online shopping experience. Also, the invention of electronic devices such as smartphones deliver easy and convenient transaction processes, further facilitating online shopping. For instance, Amazon recently released a smartphone app for their Kindle services, allowing users to conveniently access the online sales platform and review products before purchasing. In the future, the use of 3D virtual technology to market products will also take online shopping to new heights. Political/Legal In the modern day environment, firms must be cautious when they deal with international policies on online distribution. In the U.S., electronic commerce firms are regulated by the Federal Trade Commission, which regulates online advertising and the security of consumers’ personal information. On the other hand, International Consumer Protection and Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions \n----\n Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers. Demographic As the world’s population is aging rapidly, baby boomers are moving towards retirement so that they will have weaker purchasing power. Thus, generation X and Y have become companies’ target markets for product selling. These generations are technologically adept and tend to engage more in online purchasing. Based on a survey, 62 percent of Generation Y liked to purchase things online, as compared to 32 percent of those aged older than 50. Organizations \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\nEntities:\n:Cost Leadership\n:Cross-Border_Transactions\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Online_Shopping\n:Online_Shopping_Experience\n:Smartphone_App\nActivity:Online Shopping\nConcept:3D_Virtual_Technology (Technology that will take online shopping to new heights.)\nConcept:Bargaining_Power_Of_Buyers (High because customers can choose among numerous online stores for the lowest price.)\nConcept:Bargaining_Power_Of_Suppliers (Low due to the substantial number of suppliers and the vast online global distribution network.)\nConcept:E-Commerce\nConcept:Electronic_Devices (Devices such as smartphones that deliver easy and convenient transaction processes.)\nConcept:Modern Tech Support\nConcept:Online_Payment_Methods (Methods such as online banking and PayPal that create convenience in purchase transactions.)\nConcept:Threat_Of_New_Entrants (Considered low due to low capital investment costs but high infrastructure and inventory requirements.)\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nGroup:Baby Boomers\nGroup:Consumers\nGroup:Generation X\nGroup:Generation Y\nLocation:China_And_India (Emerging countries with large populations and growing disposable income.)\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nMarket:Emerging Markets\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Icpen (Finds ways to tackle consumer problems involving cross-border transactions.)\nOrganization:International Consumer Protection And Enforcement Network\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nProduct:Kindle\nTechnology:1-Click Ordering\nTechnology:3D Virtual Technology\nTechnology:Internet\nTechnology:Online Payment Methods\nTechnology:Smartphones\n----\nRelationships:\nConcept:3D_Virtual_Technology ENHANCES :Online_Shopping\nConcept:E-Commerce ENABLES Activity:Online Shopping\nConcept:Electronic_Devices FACILITATES :Online_Shopping\nConcept:Modern Tech Support FACILITATES Activity:Online Shopping\nConcept:Online_Payment_Methods ENHANCES :Online_Shopping_Experience\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nGroup:Baby Boomers LESS_INVOLVED Activity:Online Shopping\nGroup:Consumers PREFERENCE Activity:Online Shopping\nGroup:Generation X TARGET_MARKET Activity:Online Shopping\nGroup:Generation Y TARGET_MARKET Activity:Online Shopping\nLocation:China_And_India OPPORTUNITY_FOR :Online_Shopping\nMarket:Emerging Markets GROWTH Activity:Online Shopping\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Icpen ADDRESSES :Cross-Border_Transactions\nOrganization:International Consumer Protection And Enforcement Network SUPPORTS Organization:Amazon\nOrganization:Wal-Mart USES :Cost Leadership\nTechnology:3D Virtual Technology FUTURE Activity:Online Shopping\nTechnology:Internet SUPPORTS Activity:Online Shopping\nTechnology:Online Payment Methods ENHANCES Activity:Online Shopping\nTechnology:Smartphones FACILITATES Activity:Online Shopping\nDocument end\n']",ICPEN finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers.,multi_context,0.9999999999,1.0,0.75,0.9525686118288258,0.9902459810706218 +What methods does ICPEN use for cross-border online consumer issues and its effect on retailers like Amazon?,global search+vector+fulltext,"ICPEN addresses cross-border online consumer issues by developing and implementing effective solutions to enhance consumer protection and ensure fair practices in the global marketplace. These efforts aim to facilitate smoother and more secure cross-border consumer interactions. For retailers like Amazon, being supported by ICPEN can contribute to building trust with consumers, ensuring compliance with regulations, and promoting transparency in online transactions, ultimately benefiting their international operations and reputation.","[""Document start\nThis Document belongs to the source unknown\nContent: The International Consumer Protection and Enforcement Network (ICPEN) is a dedicated organization that aims to address and resolve consumer issues arising from cross-border transactions. By focusing on the complexities and challenges that consumers encounter when engaging in international transactions, ICPEN works to develop and implement effective solutions. The organization plays a crucial role in ensuring consumer protection and fostering trust in the global marketplace by tackling these cross-border challenges.\n----\nThe International Consumer Protection and Enforcement Network (ICPEN) is a dedicated organization that aims to address and resolve consumer issues arising from cross-border transactions. By focusing on the complexities and challenges that consumers encounter when engaging in international transactions, ICPEN works to develop and implement effective solutions. The organization's efforts are centered on enhancing consumer protection and ensuring fair practices in the global marketplace, thereby facilitating smoother and more secure cross-border consumer interactions.\n----\nThe International Consumer Protection and Enforcement Network (ICPEN) is a dedicated organization that aims to address and resolve consumer issues arising from cross-border transactions. By focusing on the complexities and challenges that consumers encounter when engaging in international transactions, ICPEN works to develop and implement effective solutions. The organization's efforts are centered on enhancing consumer protection and ensuring fair practices in the global marketplace, thereby facilitating smoother and more secure cross-border consumer interactions.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offers a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, regulated by the Federal Trade Commission, and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offers a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, being regulated by the Federal Trade Commission and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offer a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, regulated by the Federal Trade Commission, and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nThe International Consumer Protection and Enforcement Network (ICPEN) is an organization focused on addressing consumer issues related to cross-border transactions. Through its efforts, ICPEN seeks to find effective solutions to tackle the challenges consumers face when engaging in transactions that span different countries.\n----\nAmazon is a rapidly growing multinational e-commerce retailer based in America with a significant international presence. It faces competition from major organizations such as eBay, Barnes and Noble, and Wal-Mart. eBay and Barnes and Noble are noted for their product breadth and geographic market coverage, while Wal-Mart is recognized as the world's largest retail chain, employing a cost leadership strategy.\n\nAmazon competes with eBay, which utilizes both cost leadership and differentiation strategies. Barnes and Noble also competes with Amazon, employing an integrated focused cost leadership/differentiation strategy. Wal-Mart, another competitor, uses a cost leadership approach.\n\nAmazon is actively investing in various technologies and products, including video content, cloud services, and its Kindle product. It utilizes technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations. The company has also released a smartphone app and is located at the U.S. East Data Center.\n\nAmazon sees opportunities in emerging markets like China, which has a large population and growing disposable income. It is focused on capturing the global market and has invested in distribution centers to support this goal. The company discloses information about online sales taxes and is regulated by the Federal Trade Commission. Additionally, it receives support from the International Consumer Protection and Enforcement Network.\n----\nThe online shopping landscape is undergoing a transformative enhancement through the integration of 3D virtual technology, which aims to significantly elevate the consumer experience. This technological advancement is complemented by the widespread use of electronic devices, particularly smartphones, which are streamlining and simplifying transaction processes for online shoppers. Furthermore, emerging markets, notably China and India, are poised to play a pivotal role in the expansion of online shopping. These countries, characterized by their vast populations and rising disposable incomes, offer substantial opportunities for growth and development in the online retail sector.\n----\nThe online shopping landscape is undergoing a transformative enhancement through the integration of 3D virtual technology, which aims to significantly elevate the consumer experience. This technological advancement is complemented by the widespread use of electronic devices, particularly smartphones, which are streamlining and simplifying transaction processes for online shoppers. Furthermore, emerging markets, notably China and India, are poised to play a pivotal role in the expansion of online shopping. These countries, characterized by their vast populations and rising disposable incomes, offer substantial opportunities for growth and development in the online retail sector.\nDocument end\n""]",ICPEN finds ways to tackle consumer problems involving cross-border transactions in both goods and services. This helps to ensure participants equally benefit and reach mutual understanding. Online retailers such as Amazon should be careful to disclose online sales taxes while advertising products to other countries via online shopping platforms because different sales taxes can cause confusion to customers.,multi_context,0.9999999999,0.6666666666666666,0.8,0.9075174635825679,0.6095251499369276 +"What strategies do Amazon's book competitors use to attract price-sensitive customers and grow market share, leveraging online shopping and unique, cheap books?",vector,"Amazon's book competitors, like Barnes and Noble, employ an integrated focused cost leadership/differentiation strategy to target price-sensitive customers. They achieve this by providing books that are not readily available at a lower price point. These competitors aim to increase profitability, gain market share, and offer a wide variety of products through competitive pricing, cost leadership, and differentiation strategies. By focusing on providing unique and affordable books online, they aim to attract price-sensitive customers and compete effectively in the market against Amazon.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: \t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: \t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \nDocument end\n']","Amazon's competitors in the book industry use an integrated focused cost leadership/differentiation strategy to attract price-sensitive customers. They provide books that are not readily or commonly available at a less expensive price. They aim to increase profitability and gain market share by offering a wide variety of products to compete against Amazon, utilizing competitive pricing, cost leadership, and differentiation strategies. They also believe that the demand for online shopping will continue to grow and offer similar products as Amazon either at a lower price or accompanied with differentiated services.",multi_context,0.9999999999,1.0,0.7272727272727273,0.9553378029712812,0.9058522877045622 +"What strategies do Amazon's book competitors use to attract price-sensitive customers and grow market share, leveraging online shopping and unique, cheap books?",fulltext,"Amazon's book competitors, such as Barnes and Noble, employ an integrated focused cost leadership/differentiation strategy to target price-sensitive customers. They aim to attract these customers by offering books that are not readily available at a lower price. These competitors focus on increasing profitability, gaining market share, and providing a wide variety of products through competitive pricing, cost leadership, and differentiation strategies. By utilizing online shopping platforms and offering unique, affordable books, they aim to compete against Amazon and capture a larger market share in the book industry.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: \t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: \t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \nDocument end\n']","Amazon's competitors in the book industry use an integrated focused cost leadership/differentiation strategy to attract price-sensitive customers. They provide books that are not readily or commonly available at a less expensive price. They aim to increase profitability and gain market share by offering a wide variety of products to compete against Amazon, utilizing competitive pricing, cost leadership, and differentiation strategies. They also believe that the demand for online shopping will continue to grow and offer similar products as Amazon either at a lower price or accompanied with differentiated services.",multi_context,0.9999999999,1.0,0.8333333333333334,0.9553023290348591,0.995587268131287 +"What strategies do Amazon's book competitors use to attract price-sensitive customers and grow market share, leveraging online shopping and unique, cheap books?",entity search+vector,"Amazon's book competitors like Barnes and Noble employ strategies to attract price-sensitive customers and expand market share by leveraging online shopping and offering unique, affordable books. These competitors often utilize a combination of cost leadership and differentiation strategies. Cost leadership involves offering competitive prices to attract price-sensitive customers, while differentiation focuses on providing unique book selections or exclusive deals to stand out in the market. By combining these strategies, competitors aim to appeal to a wide range of customers seeking affordable yet distinctive book options in the online shopping landscape.","[""Document start\nThis Document belongs to the source unknown\nContent: chunks:\n- \t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n- providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n- \t\r \xa0 3 online payment methods such as online banking and PayPal create more convenience in purchase transactions, which in turn enhances customers’ online shopping experience. Also, the invention of electronic devices such as smartphones deliver easy and convenient transaction processes, further facilitating online shopping. For instance, Amazon recently released a smartphone app for their Kindle services, allowing users to conveniently access the online sales platform and review products before purchasing. In the future, the use of 3D virtual technology to market products will also take online shopping to new heights. Political/Legal In the modern day environment, firms must be cautious when they deal with international policies on online distribution. In the U.S., electronic commerce firms are regulated by the Federal Trade Commission, which regulates online advertising and the security of consumers’ personal information. On the other hand, International Consumer Protection and Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions \ncommunities:\n- Neo4j is a comprehensive graph database management system that offers a wide range of products, services, and resources to support graph data science and related applications. It provides various deployment options, including Cloud Managed Services, Self-Hosted, and Graph-As-A-Service, with Amazon AWS as a cloud provider. Neo4j's offerings include the Neo4j Graph Data Science product, Neo4j GraphQL Library, Neo4j Workspace, Neo4j Bloom visualization tool, Neo4j Developer Tools, and Neo4j Data Connectors, all of which are integral parts of the Neo4j ecosystem.\n\nThe organization supports learning and development through resources like Graphacademy, which offers free online courses and certifications, and the Neo4j Blog for daily insights. It also provides a Resource Library with white papers and data sheets, Case Studies showcasing customer success stories, and Executive Insights on graph technology.\n\nNeo4j hosts various events, including the Neo4j Events Hub for live and on-demand training, webinars, and demos, the quarterly online conference Connections, and the global Graphsummit tour. The Cypher query language is a key technology used within Neo4j for exploring and manipulating graph data.\n\nAdditionally, Neo4j includes a company structure with information about its culture, diversity, leadership, and partnerships, offering opportunities to find or become a partner through its Partner Portal.\n- Amazon.com, founded in 1993 by Jeff Benzos, initially started as an online bookstore. Over the years, it has grown into a massive retail enterprise valued at $48 billion, offering products across more than forty categories. The company experienced significant growth momentum during the Dot-Com Bubble. Jeff Benzos, the founder, played a pivotal role in its development and expansion.\n- Amazon is a rapidly growing multinational e-commerce retailer based in America with a significant international presence. It faces competition from major organizations such as eBay, Barnes and Noble, and Wal-Mart. eBay and Barnes and Noble are noted for their product breadth and geographic market coverage, while Wal-Mart is recognized as the world's largest retail chain, employing a cost leadership strategy.\n\nAmazon competes with eBay, which utilizes both cost leadership and differentiation strategies. Barnes and Noble also competes with Amazon, employing an integrated focused cost leadership/differentiation strategy. Wal-Mart, another competitor, uses a cost leadership approach.\n\nAmazon is actively investing in various technologies and products, including video content, cloud services, and its Kindle product. It utilizes technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations. The company has also released a smartphone app and is located at the U.S. East Data Center.\n\nAmazon sees opportunities in emerging markets like China, which has a large population and growing disposable income. It is focused on capturing the global market and has invested in distribution centers to support this goal. The company discloses information about online sales taxes and is regulated by the Federal Trade Commission. Additionally, it receives support from the International Consumer Protection and Enforcement Network.\nrelationships:\n- Barnes And Noble COMPETES_WITH Amazon\n- Amazon COMPETITOR Barnes And Noble\n- Amazon COMPETES_WITH Barnes And Noble\n- Amazon BENEFIT Online Shopping\n- E-Commerce ENABLES Online Shopping\nentities:\n- Organization:Barnes And Noble Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.\n- Company:Amazon.Com Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.\n- Concept:Bargaining_Power_Of_Buyers High because customers can choose among numerous online stores for the lowest price.\n- Organization:Amazon Fastest-growing, multinational e-commerce retailer in America with international presence.\n- Activity:Online Shopping \n- Online_Shopping \n- Concept:E-Commerce \n- Company:Amazon Aws \n- Online_Purchasing \n- Online_Shopping_Experience \noutside:\n nodes:\n - Organization:Ebay Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.\n - Organization:Wal-Mart World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.\n - Event:Dot-Com Bubble \n - Course:Bus 478 Seminar on Business Strategy\n - Person:Jeff Benzos Founder of Amazon.com\n - Organization:International Consumer Protection And Enforcement Network \n - Organization:Federal Trade Commission \n - Date:1993 \n - Country:India Emerging country with large population and growing disposable income.\n - Amount:$48 Billion \n relationships:\n - Organization:Amazon COMPETITOR Organization:Ebay\n - Organization:Ebay COMPETES_WITH Organization:Amazon\n - Organization:Amazon COMPETES_WITH Organization:Ebay\n - Organization:Amazon COMPETITOR Organization:Wal-Mart\n - Organization:Amazon COMPETES_WITH Organization:Wal-Mart\n - Company:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\n - Course:Bus 478 PROJECT Company:Amazon.Com\n - Company:Amazon.Com FOUNDER Person:Jeff Benzos\n - Organization:International Consumer Protection And Enforcement Network SUPPORTS Organization:Amazon\n - Organization:Federal Trade Commission REGULATES Organization:Amazon\n - Company:Amazon.Com FOUNDED Date:1993\n - Organization:Amazon OPPORTUNITY Country:India\n - Company:Amazon.Com VALUATION Amount:$48 Billion\n\nDocument end\n""]","Amazon's competitors in the book industry use an integrated focused cost leadership/differentiation strategy to attract price-sensitive customers. They provide books that are not readily or commonly available at a less expensive price. They aim to increase profitability and gain market share by offering a wide variety of products to compete against Amazon, utilizing competitive pricing, cost leadership, and differentiation strategies. They also believe that the demand for online shopping will continue to grow and offer similar products as Amazon either at a lower price or accompanied with differentiated services.",multi_context,0.9999999999,0.5,0.25,0.9615121586090064,0.7877951865157651 +"What strategies do Amazon's book competitors use to attract price-sensitive customers and grow market share, leveraging online shopping and unique, cheap books?",graph+vector,"Amazon's book competitors, such as Barnes and Noble, employ an integrated focused cost leadership/differentiation strategy to target price-sensitive customers. They achieve this by offering books that are not readily available at a lower price point. These competitors aim to increase profitability, gain market share, and provide a wide variety of products through competitive pricing, cost leadership, and differentiation strategies. By focusing on unique and affordable book offerings, along with leveraging online shopping platforms, they aim to attract price-sensitive customers and compete effectively in the market against Amazon.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: Text Content:\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Shivam Dube PLAYER Country:India\n\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: Text Content:\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Shivam Dube PLAYER Country:India\n\nDocument end\n']","Amazon's competitors in the book industry use an integrated focused cost leadership/differentiation strategy to attract price-sensitive customers. They provide books that are not readily or commonly available at a less expensive price. They aim to increase profitability and gain market share by offering a wide variety of products to compete against Amazon, utilizing competitive pricing, cost leadership, and differentiation strategies. They also believe that the demand for online shopping will continue to grow and offer similar products as Amazon either at a lower price or accompanied with differentiated services.",multi_context,0.9999999999,1.0,0.8,0.9550482196460813,0.898103060703844 +"What strategies do Amazon's book competitors use to attract price-sensitive customers and grow market share, leveraging online shopping and unique, cheap books?",graph+vector+fulltext,"Amazon's book competitors, such as Barnes and Noble, employ an integrated focused cost leadership/differentiation strategy to target price-sensitive customers and expand their market share. They achieve this by offering books that are not commonly available at a lower price point. These competitors aim to increase profitability, gain market share, and provide a wide variety of products through competitive pricing, cost leadership, and differentiation strategies. By leveraging online shopping platforms and providing unique, affordable books, they aim to attract customers seeking cost-effective options and enhance their presence in the market.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: Text Content:\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n tanked, many people chose to migrate their shopping onto an online platform. In 2011, online sales actually increased by 11 percent despite what people imagined. The reason this has \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Sales_Taxes\n:Smartphone_App\nActivity:Online Shopping\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\nTechnology:Internet\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Shivam Dube PLAYER Country:India\nPerson:Tristan Landrecht MEMBER Course:Bus 478\nPerson:Virat Kohli PLAYER Country:India\nPerson:Yashasvi Jaiswal PLAYER Country:India\nTechnology:Internet SUPPORTS Activity:Online Shopping\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: Text Content:\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n tanked, many people chose to migrate their shopping onto an online platform. In 2011, online sales actually increased by 11 percent despite what people imagined. The reason this has \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Sales_Taxes\n:Smartphone_App\nActivity:Online Shopping\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\nTechnology:Internet\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Shivam Dube PLAYER Country:India\nPerson:Tristan Landrecht MEMBER Course:Bus 478\nPerson:Virat Kohli PLAYER Country:India\nPerson:Yashasvi Jaiswal PLAYER Country:India\nTechnology:Internet SUPPORTS Activity:Online Shopping\nDocument end\n']","Amazon's competitors in the book industry use an integrated focused cost leadership/differentiation strategy to attract price-sensitive customers. They provide books that are not readily or commonly available at a less expensive price. They aim to increase profitability and gain market share by offering a wide variety of products to compete against Amazon, utilizing competitive pricing, cost leadership, and differentiation strategies. They also believe that the demand for online shopping will continue to grow and offer similar products as Amazon either at a lower price or accompanied with differentiated services.",multi_context,0.9999999999,1.0,1.0,0.9553023290348591,0.9175976729605386 +"What strategies do Amazon's book competitors use to attract price-sensitive customers and grow market share, leveraging online shopping and unique, cheap books?",global search+vector+fulltext,"Amazon's book competitors employ various strategies to attract price-sensitive customers and expand their market share in the realm of online shopping. eBay, Barnes and Noble, and Wal-Mart utilize different approaches to cater to this segment: + +1. **eBay**: Utilizes both cost leadership and differentiation strategies to appeal to price-sensitive customers. It offers a wide range of products, including books, at competitive prices while also providing a unique platform for auctions and second-hand items. + +2. **Barnes and Noble**: Integrates a focused cost leadership/differentiation strategy to stand out in the market. By offering a mix of affordable books along with unique and high-quality selections, they target price-sensitive customers seeking value and variety. + +3. **Wal-Mart**: Focuses on a cost leadership approach, leveraging its vast retail chain to provide competitive pricing on books and other products. By emphasizing affordability and a wide selection, Wal-Mart aims to attract price-sensitive customers looking for budget-friendly options. + +These competitors aim to leverage online shopping platforms to reach a broader audience of price-sensitive customers while offering unique and affordable book selections to enhance their market share in the competitive e-commerce landscape.","[""Document start\nThis Document belongs to the source unknown\nContent: Amazon is a rapidly growing multinational e-commerce retailer based in America with a significant international presence. It faces competition from major organizations such as eBay, Barnes and Noble, and Wal-Mart. eBay and Barnes and Noble are noted for their product breadth and geographic market coverage, while Wal-Mart is recognized as the world's largest retail chain, employing a cost leadership strategy.\n\nAmazon competes with eBay, which utilizes both cost leadership and differentiation strategies. Barnes and Noble also competes with Amazon, employing an integrated focused cost leadership/differentiation strategy. Wal-Mart, another competitor, uses a cost leadership approach.\n\nAmazon is actively investing in various technologies and products, including video content, cloud services, and its Kindle product. It utilizes technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations. The company has also released a smartphone app and is located at the U.S. East Data Center.\n\nAmazon sees opportunities in emerging markets like China, which has a large population and growing disposable income. It is focused on capturing the global market and has invested in distribution centers to support this goal. The company discloses information about online sales taxes and is regulated by the Federal Trade Commission. Additionally, it receives support from the International Consumer Protection and Enforcement Network.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offers a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, being regulated by the Federal Trade Commission and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offers a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, regulated by the Federal Trade Commission, and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offer a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, regulated by the Federal Trade Commission, and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nThe community consists of a group of individuals, Jin Can Chen, Jae Kim, Jessica Zhang, John Chen, and Tristan Landrecht, who are enrolled in Bus 478, a seminar focused on business strategy. This course involves a collaborative or team-based approach, suggesting that these members work closely together on projects or discussions related to business strategy. Additionally, the community is linked to Amazon.com, a company founded in 1993 by Jeff Benzos. Originally an online bookstore, Amazon has evolved into a vast retail enterprise valued at $48 billion, offering a wide range of products across more than forty categories. The company saw substantial growth during the Dot-Com Bubble, with Jeff Benzos playing a crucial role in its expansion and success. This connection to Amazon may indicate that the course or group discussions could involve case studies or strategic analyses of Amazon's business model and growth trajectory.\n----\nAmazon.com, founded in 1993 by Jeff Benzos, initially started as an online bookstore. Over the years, it has grown into a massive retail enterprise valued at $48 billion, offering products across more than forty categories. The company experienced significant growth momentum during the Dot-Com Bubble. Jeff Benzos, the founder, played a pivotal role in its development and expansion.\n----\nThe community consists of individuals and entities connected through educational and business endeavors. Jin Can Chen, Jae Kim, Jessica Zhang, John Chen, and Tristan Landrecht are all participants in Bus 478, a seminar focused on business strategy, which emphasizes teamwork and collaboration. This educational setting likely fosters skills relevant to business growth and strategy, akin to those demonstrated by Amazon.com. Founded in 1993 by Jeff Benzos, Amazon began as an online bookstore and evolved into a vast retail empire valued at $48 billion, offering a diverse range of products across more than forty categories. The company's significant expansion, particularly during the Dot-Com Bubble, highlights the importance of strategic business planning and leadership, as exemplified by Benzos' pivotal role in its success. This connection between the educational focus of Bus 478 and the business strategies employed by Amazon underscores the relevance of strategic thinking in both academic and real-world business contexts.\n----\nThe community consists of individuals and entities connected through educational and business endeavors. Jin Can Chen, Jae Kim, Jessica Zhang, John Chen, and Tristan Landrecht are all participants in Bus 478, a seminar focused on business strategy, which emphasizes teamwork and collaboration. This educational setting likely fosters skills relevant to business growth and strategy, akin to those demonstrated by Amazon.com. Founded in 1993 by Jeff Benzos, Amazon began as an online bookstore and evolved into a vast retail empire valued at $48 billion, offering a diverse range of products across more than forty categories. The company's significant expansion, particularly during the Dot-Com Bubble, highlights the importance of strategic business planning and leadership, as exemplified by Benzos' pivotal role in its success. This connection between the educational focus of Bus 478 and the business strategies employed by Amazon underscores the relevance of strategic thinking in both academic and real-world business contexts.\n----\nThe online shopping landscape is undergoing a transformative enhancement through the integration of 3D virtual technology, which aims to significantly elevate the consumer experience. This technological advancement is complemented by the widespread use of electronic devices, particularly smartphones, which are streamlining and simplifying transaction processes for online shoppers. Furthermore, emerging markets, notably China and India, are poised to play a pivotal role in the expansion of online shopping. These countries, characterized by their vast populations and rising disposable incomes, offer substantial opportunities for growth and development in the online retail sector.\n----\nThe online shopping landscape is undergoing a transformative enhancement through the integration of 3D virtual technology, which aims to significantly elevate the consumer experience. This technological advancement is complemented by the widespread use of electronic devices, particularly smartphones, which are streamlining and simplifying transaction processes for online shoppers. Furthermore, emerging markets, notably China and India, are poised to play a pivotal role in the expansion of online shopping. These countries, characterized by their vast populations and rising disposable incomes, offer substantial opportunities for growth and development in the online retail sector.\nDocument end\n""]","Amazon's competitors in the book industry use an integrated focused cost leadership/differentiation strategy to attract price-sensitive customers. They provide books that are not readily or commonly available at a less expensive price. They aim to increase profitability and gain market share by offering a wide variety of products to compete against Amazon, utilizing competitive pricing, cost leadership, and differentiation strategies. They also believe that the demand for online shopping will continue to grow and offer similar products as Amazon either at a lower price or accompanied with differentiated services.",multi_context,0.9999999999,0.5,0.14285714285714285,0.967728078973633,0.8039721568085061 +"What strategies are Amazon's book rivals using for price-sensitive customers and market growth, and its impact on Amazon's long-term investment focus?",vector,"Amazon's book rivals, such as Barnes and Noble, are employing an integrated focused cost leadership/differentiation strategy to target price-sensitive customers. They aim to offer books not readily available at a lower price to compete with Amazon. This strategy impacts Amazon's long-term investment focus by potentially influencing the need for margin expansion to prevent share price drops. While Amazon focuses on long-term investments like video content and distribution centers, the competition's pricing strategies may necessitate Amazon to balance its investments to remain competitive in the market.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: \t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: \t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\nDocument end\n']","Amazon's book rivals are using an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. They aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through competitive pricing, cost leadership, and differentiation strategies. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. This intense competition impacts Amazon's long-term investment focus, as the company needs to keep investing in new projects that generate more revenue to reflect the value of the company, despite the increasing expenditures in some of its services.",multi_context,0.9999999999,0.75,0.6363636363636364,0.9149586709793368,0.544215279154729 +"What strategies are Amazon's book rivals using for price-sensitive customers and market growth, and its impact on Amazon's long-term investment focus?",fulltext,"Amazon's book rivals, such as Barnes and Noble, are employing an integrated focused cost leadership/differentiation strategy to target price-sensitive customers. They achieve this by offering books not readily available at a lower price. This strategy aims to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon. The impact on Amazon's long-term investment focus is that while Amazon is interested in long-term investments like video content and distribution centers, it faces challenges in predicting the realization of benefits from these investments due to the need for margin expansion to prevent share price drops.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: \t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: \t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\nDocument end\n']","Amazon's book rivals are using an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. They aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through competitive pricing, cost leadership, and differentiation strategies. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. This intense competition impacts Amazon's long-term investment focus, as the company needs to keep investing in new projects that generate more revenue to reflect the value of the company, despite the increasing expenditures in some of its services.",multi_context,0.9999999999,1.0,0.9,0.9429061355024674,0.8209237046096777 +"What strategies are Amazon's book rivals using for price-sensitive customers and market growth, and its impact on Amazon's long-term investment focus?",entity search+vector,"Amazon's book rivals, like Barnes and Noble, are likely employing strategies to attract price-sensitive customers by offering competitive pricing, discounts, and promotions. To drive market growth, these rivals may focus on expanding their product offerings, enhancing customer experience, and investing in marketing campaigns. These strategies could impact Amazon's long-term investment focus by potentially prompting Amazon to adjust its pricing strategies, invest more in customer retention and acquisition, or explore new market segments to maintain its competitive edge in the evolving e-commerce landscape.","[""Document start\nThis Document belongs to the source unknown\nContent: chunks:\n- providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n- \t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n- \t\r \xa0 3 online payment methods such as online banking and PayPal create more convenience in purchase transactions, which in turn enhances customers’ online shopping experience. Also, the invention of electronic devices such as smartphones deliver easy and convenient transaction processes, further facilitating online shopping. For instance, Amazon recently released a smartphone app for their Kindle services, allowing users to conveniently access the online sales platform and review products before purchasing. In the future, the use of 3D virtual technology to market products will also take online shopping to new heights. Political/Legal In the modern day environment, firms must be cautious when they deal with international policies on online distribution. In the U.S., electronic commerce firms are regulated by the Federal Trade Commission, which regulates online advertising and the security of consumers’ personal information. On the other hand, International Consumer Protection and Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions \ncommunities:\n- Neo4j is a comprehensive graph database management system that offers a wide range of products, services, and resources to support graph data science and related applications. It provides various deployment options, including Cloud Managed Services, Self-Hosted, and Graph-As-A-Service, with Amazon AWS as a cloud provider. Neo4j's offerings include the Neo4j Graph Data Science product, Neo4j GraphQL Library, Neo4j Workspace, Neo4j Bloom visualization tool, Neo4j Developer Tools, and Neo4j Data Connectors, all of which are integral parts of the Neo4j ecosystem.\n\nThe organization supports learning and development through resources like Graphacademy, which offers free online courses and certifications, and the Neo4j Blog for daily insights. It also provides a Resource Library with white papers and data sheets, Case Studies showcasing customer success stories, and Executive Insights on graph technology.\n\nNeo4j hosts various events, including the Neo4j Events Hub for live and on-demand training, webinars, and demos, the quarterly online conference Connections, and the global Graphsummit tour. The Cypher query language is a key technology used within Neo4j for exploring and manipulating graph data.\n\nAdditionally, Neo4j includes a company structure with information about its culture, diversity, leadership, and partnerships, offering opportunities to find or become a partner through its Partner Portal.\n- Amazon.com, founded in 1993 by Jeff Benzos, initially started as an online bookstore. Over the years, it has grown into a massive retail enterprise valued at $48 billion, offering products across more than forty categories. The company experienced significant growth momentum during the Dot-Com Bubble. Jeff Benzos, the founder, played a pivotal role in its development and expansion.\n- Amazon is a rapidly growing multinational e-commerce retailer based in America with a significant international presence. It faces competition from major organizations such as eBay, Barnes and Noble, and Wal-Mart. eBay and Barnes and Noble are noted for their product breadth and geographic market coverage, while Wal-Mart is recognized as the world's largest retail chain, employing a cost leadership strategy.\n\nAmazon competes with eBay, which utilizes both cost leadership and differentiation strategies. Barnes and Noble also competes with Amazon, employing an integrated focused cost leadership/differentiation strategy. Wal-Mart, another competitor, uses a cost leadership approach.\n\nAmazon is actively investing in various technologies and products, including video content, cloud services, and its Kindle product. It utilizes technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations. The company has also released a smartphone app and is located at the U.S. East Data Center.\n\nAmazon sees opportunities in emerging markets like China, which has a large population and growing disposable income. It is focused on capturing the global market and has invested in distribution centers to support this goal. The company discloses information about online sales taxes and is regulated by the Federal Trade Commission. Additionally, it receives support from the International Consumer Protection and Enforcement Network.\nentities:\n- Organization:Amazon Fastest-growing, multinational e-commerce retailer in America with international presence.\n- Company:Amazon Aws \n- Company:Amazon.Com Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.\n- Concept:Bargaining_Power_Of_Buyers High because customers can choose among numerous online stores for the lowest price.\n- Organization:Barnes And Noble Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.\n- Group:Consumers \n- Electronic_Commerce_Firms \n- Concept:E-Commerce \n- Organization:Amazon Cooperation Treaty Organization \n- Global_Market \nrelationships:\n- Amazon COMPETITOR Barnes And Noble\n- Amazon COMPETES_WITH Barnes And Noble\n- Amazon CAPTURES Global_Market\n- Barnes And Noble COMPETES_WITH Amazon\noutside:\n nodes:\n - Organization:Ebay Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.\n - Activity:Online Shopping \n - Organization:Wal-Mart World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.\n - Organization:Federal Trade Commission \n - Country:India Emerging country with large population and growing disposable income.\n - Country:China Emerging country with large population and growing disposable income.\n - Technology:Cloud \n - Product:Video Content \n - Technology:Elastic Block Storage (Ebs) \n - Organization:International Consumer Protection And Enforcement Network \n relationships:\n - Organization:Amazon COMPETITOR Organization:Ebay\n - Organization:Ebay COMPETES_WITH Organization:Amazon\n - Organization:Amazon COMPETES_WITH Organization:Ebay\n - Organization:Amazon BENEFIT Activity:Online Shopping\n - Group:Consumers PREFERENCE Activity:Online Shopping\n - Concept:E-Commerce ENABLES Activity:Online Shopping\n - Organization:Amazon COMPETITOR Organization:Wal-Mart\n - Organization:Amazon COMPETES_WITH Organization:Wal-Mart\n - Organization:Federal Trade Commission REGULATES Organization:Amazon\n - Organization:Amazon OPPORTUNITY Country:India\n - Organization:Amazon OPPORTUNITY Country:China\n - Organization:Amazon INVESTS_IN Technology:Cloud\n - Organization:Amazon INVESTS_IN Product:Video Content\n - Organization:Amazon USES Technology:Elastic Block Storage (Ebs)\n - Organization:International Consumer Protection And Enforcement Network SUPPORTS Organization:Amazon\n\nDocument end\n""]","Amazon's book rivals are using an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. They aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through competitive pricing, cost leadership, and differentiation strategies. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. This intense competition impacts Amazon's long-term investment focus, as the company needs to keep investing in new projects that generate more revenue to reflect the value of the company, despite the increasing expenditures in some of its services.",multi_context,0.9999999999,0.5,0.0,0.9504468591459928,0.7167896146801386 +"What strategies are Amazon's book rivals using for price-sensitive customers and market growth, and its impact on Amazon's long-term investment focus?",graph+vector,"Amazon's book rivals, such as Barnes and Noble, are employing an integrated focused cost leadership/differentiation strategy to target price-sensitive customers. They achieve this by offering books not commonly available at a lower price. This strategy aims to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon. The impact of these strategies on Amazon's long-term investment focus is significant. Amazon is focusing on long-term investments like video content and distribution centers, but challenges arise due to the need for margin expansion to prevent share price drops. Despite these challenges, Amazon must continue investing in new revenue-generating projects to maintain competitiveness in the industry.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: Text Content:\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: Text Content:\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER\nDocument end\n']","Amazon's book rivals are using an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. They aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through competitive pricing, cost leadership, and differentiation strategies. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. This intense competition impacts Amazon's long-term investment focus, as the company needs to keep investing in new projects that generate more revenue to reflect the value of the company, despite the increasing expenditures in some of its services.",multi_context,0.9999999999,1.0,0.9090909090909091,0.8989058196332955,0.7933393991795576 +"What strategies are Amazon's book rivals using for price-sensitive customers and market growth, and its impact on Amazon's long-term investment focus?",graph+vector+fulltext,"Amazon's book rivals, such as Barnes and Noble, are employing an integrated focused cost leadership/differentiation strategy to target price-sensitive customers. They achieve this by offering books not commonly available at a lower price. This strategy aims to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon. The impact on Amazon's long-term investment focus is that while Amazon is interested in long-term investments like video content and distribution centers, it faces challenges in predicting the realization of benefits from these investments due to the need for margin expansion to prevent share price drops.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: Text Content:\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: Text Content:\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Purchasing\n:Online_Sales_Taxes\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nDemographic_group:Generation_X_And_Y (Technologically adept generations that engage more in online purchasing.)\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nDemographic_group:Generation_X_And_Y ENGAGES_IN :Online_Purchasing\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER\nDocument end\n']","Amazon's book rivals are using an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. They aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through competitive pricing, cost leadership, and differentiation strategies. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. This intense competition impacts Amazon's long-term investment focus, as the company needs to keep investing in new projects that generate more revenue to reflect the value of the company, despite the increasing expenditures in some of its services.",multi_context,0.9999999999,1.0,0.9,0.9429061355024674,0.7996236241211843 +"What strategies are Amazon's book rivals using for price-sensitive customers and market growth, and its impact on Amazon's long-term investment focus?",global search+vector+fulltext,"eBay, Barnes and Noble, and Wal-Mart, as Amazon's book rivals, employ distinct strategies tailored for price-sensitive customers and market expansion. eBay combines cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart emphasizes cost leadership. These strategies influence how these competitors attract price-sensitive customers and drive market growth. Amazon, in response, focuses on long-term investments in technologies like video content, cloud services, and product innovation to maintain its competitive edge and global market presence amidst these strategic dynamics.","[""Document start\nThis Document belongs to the source unknown\nContent: The community consists of a group of individuals, Jin Can Chen, Jae Kim, Jessica Zhang, John Chen, and Tristan Landrecht, who are enrolled in Bus 478, a seminar focused on business strategy. This course involves a collaborative or team-based approach, suggesting that these members work closely together on projects or discussions related to business strategy. Additionally, the community is linked to Amazon.com, a company founded in 1993 by Jeff Benzos. Originally an online bookstore, Amazon has evolved into a vast retail enterprise valued at $48 billion, offering a wide range of products across more than forty categories. The company saw substantial growth during the Dot-Com Bubble, with Jeff Benzos playing a crucial role in its expansion and success. This connection to Amazon may indicate that the course or group discussions could involve case studies or strategic analyses of Amazon's business model and growth trajectory.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offers a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, regulated by the Federal Trade Commission, and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offers a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, being regulated by the Federal Trade Commission and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nAmazon is a rapidly growing multinational e-commerce retailer based in America with a significant international presence. It faces competition from major organizations such as eBay, Barnes and Noble, and Wal-Mart. eBay and Barnes and Noble are noted for their product breadth and geographic market coverage, while Wal-Mart is recognized as the world's largest retail chain, employing a cost leadership strategy.\n\nAmazon competes with eBay, which utilizes both cost leadership and differentiation strategies. Barnes and Noble also competes with Amazon, employing an integrated focused cost leadership/differentiation strategy. Wal-Mart, another competitor, uses a cost leadership approach.\n\nAmazon is actively investing in various technologies and products, including video content, cloud services, and its Kindle product. It utilizes technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations. The company has also released a smartphone app and is located at the U.S. East Data Center.\n\nAmazon sees opportunities in emerging markets like China, which has a large population and growing disposable income. It is focused on capturing the global market and has invested in distribution centers to support this goal. The company discloses information about online sales taxes and is regulated by the Federal Trade Commission. Additionally, it receives support from the International Consumer Protection and Enforcement Network.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offer a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, regulated by the Federal Trade Commission, and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nAmazon.com, founded in 1993 by Jeff Benzos, initially started as an online bookstore. Over the years, it has grown into a massive retail enterprise valued at $48 billion, offering products across more than forty categories. The company experienced significant growth momentum during the Dot-Com Bubble. Jeff Benzos, the founder, played a pivotal role in its development and expansion.\n----\nThe community consists of individuals and entities connected through educational and business endeavors. Jin Can Chen, Jae Kim, Jessica Zhang, John Chen, and Tristan Landrecht are all participants in Bus 478, a seminar focused on business strategy, which emphasizes teamwork and collaboration. This educational setting likely fosters skills relevant to business growth and strategy, akin to those demonstrated by Amazon.com. Founded in 1993 by Jeff Benzos, Amazon began as an online bookstore and evolved into a vast retail empire valued at $48 billion, offering a diverse range of products across more than forty categories. The company's significant expansion, particularly during the Dot-Com Bubble, highlights the importance of strategic business planning and leadership, as exemplified by Benzos' pivotal role in its success. This connection between the educational focus of Bus 478 and the business strategies employed by Amazon underscores the relevance of strategic thinking in both academic and real-world business contexts.\n----\nThe community consists of individuals and entities connected through educational and business endeavors. Jin Can Chen, Jae Kim, Jessica Zhang, John Chen, and Tristan Landrecht are all participants in Bus 478, a seminar focused on business strategy, which emphasizes teamwork and collaboration. This educational setting likely fosters skills relevant to business growth and strategy, akin to those demonstrated by Amazon.com. Founded in 1993 by Jeff Benzos, Amazon began as an online bookstore and evolved into a vast retail empire valued at $48 billion, offering a diverse range of products across more than forty categories. The company's significant expansion, particularly during the Dot-Com Bubble, highlights the importance of strategic business planning and leadership, as exemplified by Benzos' pivotal role in its success. This connection between the educational focus of Bus 478 and the business strategies employed by Amazon underscores the relevance of strategic thinking in both academic and real-world business contexts.\n----\nGeneration X and Y, recognized for their proficiency with technology, are demographic cohorts that frequently participate in online shopping activities. These groups are characterized by their comfort and familiarity with digital platforms, which facilitates their engagement in e-commerce. Their technological adeptness not only influences their purchasing habits but also reflects broader trends in consumer behavior, where digital literacy plays a crucial role in shaping market dynamics. As active participants in the online marketplace, Generation X and Y contribute significantly to the growth and evolution of e-commerce, highlighting the importance of targeting these demographics in digital marketing strategies.\n----\nThe online shopping landscape is undergoing a transformative enhancement through the integration of 3D virtual technology, which aims to significantly elevate the consumer experience. This technological advancement is complemented by the widespread use of electronic devices, particularly smartphones, which are streamlining and simplifying transaction processes for online shoppers. Furthermore, emerging markets, notably China and India, are poised to play a pivotal role in the expansion of online shopping. These countries, characterized by their vast populations and rising disposable incomes, offer substantial opportunities for growth and development in the online retail sector.\nDocument end\n""]","Amazon's book rivals are using an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. They aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through competitive pricing, cost leadership, and differentiation strategies. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. This intense competition impacts Amazon's long-term investment focus, as the company needs to keep investing in new projects that generate more revenue to reflect the value of the company, despite the increasing expenditures in some of its services.",multi_context,0.9999999999,0.25,0.5333333333333333,0.9003929990624776,0.7177808409752562 +What were the 2012 issues with Amazon's EBS at the U.S. East center and their impact on customer service and future investments?,vector,"In 2012, Amazon's Elastic Block Storage (EBS) service experienced multiple downtimes at the U.S. East data center in Virginia. These outages had a significant impact on customer service, causing inconvenience and discomfort for regular website users. As a result, Amazon faced challenges in maintaining customer satisfaction and reliability. These issues highlighted the importance of major upgrades to prevent future service disruptions and emphasized the need for strategic investments in infrastructure to enhance the resilience of their data centers and improve overall customer experience.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: \t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: \t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \nDocument end\n']","In 2012, Amazon's Elastic Block Storage (EBS) service at the U.S. East data center in Virginia experienced several outages due to an electric outage. This was a significant issue as this data center is the biggest and oldest one. These outages caused inconvenience and discomfort to regular users of the website. The company recognized the need for major upgrades to this data center to prevent future service disruptions. The issues also impacted future investments, with Amazon planning to reduce investments in initiatives like Kindle and Cloud.",multi_context,0.9999999999,1.0,0.5,0.932155520829277,0.868596089410279 +What were the 2012 issues with Amazon's EBS at the U.S. East center and their impact on customer service and future investments?,fulltext,"In 2012, Amazon's Elastic Block Storage (EBS) service experienced multiple downtimes at the U.S. East data center in Virginia. These outages had a significant impact on customer service, causing inconvenience and discomfort for regular website users. As a result, Amazon needed to make major upgrades to the U.S. East data center to prevent such service disruptions in the future. These issues highlighted the importance of investing in infrastructure to ensure reliable services and maintain customer satisfaction.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n since the existing major competitors, such as Amazon, have established a loyal customer base. Bargaining Power of Suppliers Suppliers have little bargaining power due to the substantial number of suppliers available and the vast expanse of the online global distribution network. Many suppliers rely on key online retailers such as Amazon to engage in bulk purchasing. Thus, online retailers can easily switch to another supplier for lower price and better quality. Bargaining power of suppliers to Amazon is particularly low since suppliers do not require payment until 35 days after the confirmation of sales. Bargaining Power of Buyers The bargaining power of buyers is high. Customers have the options to choose among numerous online stores for the lowest price products and services due to the completely available \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\nDocument end\n']","In 2012, Amazon's Elastic Block Storage (EBS) service at the U.S. East data center in Virginia experienced several outages due to an electric outage. This was a significant issue as this data center is the biggest and oldest one. These outages caused inconvenience and discomfort to regular users of the website. The company recognized the need for major upgrades to this data center to prevent future service disruptions. The issues also impacted future investments, with Amazon planning to reduce investments in initiatives like Kindle and Cloud.",multi_context,0.9999999999,1.0,0.5555555555555556,0.9321494024653637,0.8578405670500375 +What were the 2012 issues with Amazon's EBS at the U.S. East center and their impact on customer service and future investments?,graph+vector,"In 2012, Amazon's Elastic Block Storage (EBS) service at the U.S. East data center experienced multiple outages, impacting customer service reliability. These issues caused inconvenience and discomfort for customers relying on Amazon's services. As a result, Amazon needed to make major upgrades to the U.S. East data center to prevent future service disruptions. These incidents highlighted the importance of investing in infrastructure to ensure uninterrupted service delivery and maintain customer satisfaction.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: Text Content:\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Sales_Taxes\n:Online_Shopping_Experience\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nConcept:Online_Payment_Methods (Methods such as online banking and PayPal that create convenience in purchase transactions.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nConcept:Online_Payment_Methods ENHANCES :Online_Shopping_Experience\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: Text Content:\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Sales_Taxes\n:Online_Shopping_Experience\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nConcept:Online_Payment_Methods (Methods such as online banking and PayPal that create convenience in purchase transactions.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nConcept:Online_Payment_Methods ENHANCES :Online_Shopping_Experience\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nDocument end\n']","In 2012, Amazon's Elastic Block Storage (EBS) service at the U.S. East data center in Virginia experienced several outages due to an electric outage. This was a significant issue as this data center is the biggest and oldest one. These outages caused inconvenience and discomfort to regular users of the website. The company recognized the need for major upgrades to this data center to prevent future service disruptions. The issues also impacted future investments, with Amazon planning to reduce investments in initiatives like Kindle and Cloud.",multi_context,0.9999999999,1.0,0.7777777777777778,0.9339821431522823,0.8298531266923304 +What were the 2012 issues with Amazon's EBS at the U.S. East center and their impact on customer service and future investments?,graph+vector+fulltext,"In 2012, Amazon faced several downtimes with its Elastic Block Storage (EBS) service at the U.S. East data center, leading to disruptions in customer service. These outages caused inconvenience and discomfort for customers who regularly used the website. As a result, Amazon needed to make major upgrades to the U.S. East data center to prevent such service interruptions in the future. These incidents highlighted the importance of investing in infrastructure to ensure reliable services and maintain customer satisfaction.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: Text Content:\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Sales_Taxes\n:Online_Shopping_Experience\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nConcept:Online_Payment_Methods (Methods such as online banking and PayPal that create convenience in purchase transactions.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nConcept:Online_Payment_Methods ENHANCES :Online_Shopping_Experience\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: Text Content:\n\t\r \xa0 7 electric outage. The main problem comes from the Amazon’s U.S. East data center in Virginia, which is the biggest and the oldest data center that has been causing outage issues. The company needs to do major upgrades on the U.S. East data center to prevent the services from going down in the future. Otherwise, the server crashes can bring inconvenience and discomfort to the customers who use the website regularly. Some of Amazon’s services such as Kindle and Cloud have been increasing expenditures throughout the company. Amazon is planning to reduce investments in the Kindle and Cloud initiatives next year. In order to remain competitive in the industry, Amazon should keep investing in new projects that generate more revenue to reflect the value of the company. While Amazon’s main interest is in long-term investments, such as video content and distribution centers, it is difficult to predict when the benefits from these investments will be realized\n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Sales_Taxes\n:Online_Shopping_Experience\n:Smartphone_App\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nConcept:Online_Payment_Methods (Methods such as online banking and PayPal that create convenience in purchase transactions.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nConcept:Online_Payment_Methods ENHANCES :Online_Shopping_Experience\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nDocument end\n']","In 2012, Amazon's Elastic Block Storage (EBS) service at the U.S. East data center in Virginia experienced several outages due to an electric outage. This was a significant issue as this data center is the biggest and oldest one. These outages caused inconvenience and discomfort to regular users of the website. The company recognized the need for major upgrades to this data center to prevent future service disruptions. The issues also impacted future investments, with Amazon planning to reduce investments in initiatives like Kindle and Cloud.",multi_context,0.9999999999,1.0,0.7777777777777778,0.9227835889993118,0.8289740705888251 +How do rivals target cost-conscious readers and compete with Amazon?,vector,"Rivals target cost-conscious readers and compete with Amazon by employing strategies like focused cost leadership and differentiation. For example, Barnes and Noble, a major competitor, uses an integrated focused cost leadership/differentiation strategy to offer books at competitive prices and provide unique selections not easily found elsewhere. This approach aims to attract price-sensitive consumers while providing value through product variety and quality service.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: \t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: \t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\nDocument end\n']","Rivals target cost-conscious readers and compete with Amazon by pursuing an integrated focused cost leadership/differentiation strategy. They provide books that are not readily or commonly available at a less expensive price. They aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers.",reasoning,0.9999999999,1.0,1.0,0.9855041512534686,0.721496872867419 +How do rivals target cost-conscious readers and compete with Amazon?,fulltext,"Rivals target cost-conscious readers and compete with Amazon by employing strategies like focused cost leadership and differentiation. They aim to offer products not commonly available at lower prices, utilize competitive pricing, and provide differentiated services. By focusing on cost-effective approaches, providing a wide variety of products, and enhancing customer service, competitors strive to attract and retain cost-conscious readers in the market while challenging Amazon's market share.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: \t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: \t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\nDocument end\n']","Rivals target cost-conscious readers and compete with Amazon by pursuing an integrated focused cost leadership/differentiation strategy. They provide books that are not readily or commonly available at a less expensive price. They aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers.",reasoning,0.9999999999,1.0,0.8181818181818182,0.9742459416659807,0.6190315441384282 +How do rivals target cost-conscious readers and compete with Amazon?,entity search+vector,"Rivals target cost-conscious readers and compete with Amazon by offering competitive pricing, deals, and discounts to attract price-sensitive customers. They may also focus on providing value-added services, unique product selections, and efficient delivery options to differentiate themselves from Amazon. Additionally, rivals can leverage their brand reputation, customer service, and loyalty programs to build customer trust and loyalty in the face of Amazon's dominance in the market.","[""Document start\nThis Document belongs to the source unknown\nContent: chunks:\n- providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n- \t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n- \t\r \xa0 3 online payment methods such as online banking and PayPal create more convenience in purchase transactions, which in turn enhances customers’ online shopping experience. Also, the invention of electronic devices such as smartphones deliver easy and convenient transaction processes, further facilitating online shopping. For instance, Amazon recently released a smartphone app for their Kindle services, allowing users to conveniently access the online sales platform and review products before purchasing. In the future, the use of 3D virtual technology to market products will also take online shopping to new heights. Political/Legal In the modern day environment, firms must be cautious when they deal with international policies on online distribution. In the U.S., electronic commerce firms are regulated by the Federal Trade Commission, which regulates online advertising and the security of consumers’ personal information. On the other hand, International Consumer Protection and Enforcement Network (ICPEN) finds ways to tackle consumer problems involving cross-border transactions \ncommunities:\n- Amazon.com, founded in 1993 by Jeff Benzos, initially started as an online bookstore. Over the years, it has grown into a massive retail enterprise valued at $48 billion, offering products across more than forty categories. The company experienced significant growth momentum during the Dot-Com Bubble. Jeff Benzos, the founder, played a pivotal role in its development and expansion.\n- Amazon is a rapidly growing multinational e-commerce retailer based in America with a significant international presence. It faces competition from major organizations such as eBay, Barnes and Noble, and Wal-Mart. eBay and Barnes and Noble are noted for their product breadth and geographic market coverage, while Wal-Mart is recognized as the world's largest retail chain, employing a cost leadership strategy.\n\nAmazon competes with eBay, which utilizes both cost leadership and differentiation strategies. Barnes and Noble also competes with Amazon, employing an integrated focused cost leadership/differentiation strategy. Wal-Mart, another competitor, uses a cost leadership approach.\n\nAmazon is actively investing in various technologies and products, including video content, cloud services, and its Kindle product. It utilizes technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations. The company has also released a smartphone app and is located at the U.S. East Data Center.\n\nAmazon sees opportunities in emerging markets like China, which has a large population and growing disposable income. It is focused on capturing the global market and has invested in distribution centers to support this goal. The company discloses information about online sales taxes and is regulated by the Federal Trade Commission. Additionally, it receives support from the International Consumer Protection and Enforcement Network.\n- Amazon is a rapidly growing multinational e-commerce retailer based in America with a significant international presence. It faces competition from major organizations such as eBay, Barnes and Noble, and Wal-Mart. eBay and Barnes and Noble are noted for their product breadth and geographic market coverage, while Wal-Mart is recognized as the world's largest retail chain, employing a cost leadership strategy.\n\nAmazon competes with eBay, which utilizes both cost leadership and differentiation strategies. Barnes and Noble also competes with Amazon, employing an integrated focused cost leadership/differentiation strategy. Wal-Mart, another competitor, uses a cost leadership approach.\n\nAmazon is actively investing in various technologies and products, including video content, cloud services, and its Kindle product. It utilizes technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations. The company has also released a smartphone app and is located at the U.S. East Data Center.\n\nAmazon sees opportunities in emerging markets like China, which has a large population and growing disposable income. It is focused on capturing the global market and has invested in distribution centers to support this goal. The company discloses information about online sales taxes and is regulated by the Federal Trade Commission. Additionally, it receives support from the International Consumer Protection and Enforcement Network.\nentities:\n- Organization:Amazon Fastest-growing, multinational e-commerce retailer in America with international presence.\n- Company:Amazon.Com Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.\n- Organization:Barnes And Noble Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.\n- Group:Consumers \n- Online_Shopping \n- Concept:E-Commerce \n- Product:Kindle \n- Activity:Online Shopping \n- Online_Purchasing \n- Online_Shopping_Experience \nrelationships:\n- Amazon COMPETITOR Barnes And Noble\n- Amazon COMPETES_WITH Barnes And Noble\n- Amazon INVESTS_IN Kindle\n- Amazon BENEFIT Online Shopping\n- Barnes And Noble COMPETES_WITH Amazon\n- Consumers PREFERENCE Online Shopping\n- E-Commerce ENABLES Online Shopping\noutside:\n nodes:\n - Organization:Ebay Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.\n - Organization:Wal-Mart World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.\n - Country:China Emerging country with large population and growing disposable income.\n - Location:Distribution Centers \n - Technology:Cloud \n - Product:Video Content \n - Country:India Emerging country with large population and growing disposable income.\n - Technology:Elastic Block Storage (Ebs) \n - Organization:Federal Trade Commission \n - Organization:International Consumer Protection And Enforcement Network \n relationships:\n - Organization:Amazon COMPETITOR Organization:Ebay\n - Organization:Ebay COMPETES_WITH Organization:Amazon\n - Organization:Amazon COMPETES_WITH Organization:Ebay\n - Organization:Amazon COMPETITOR Organization:Wal-Mart\n - Organization:Amazon COMPETES_WITH Organization:Wal-Mart\n - Organization:Amazon OPPORTUNITY Country:China\n - Organization:Amazon INVESTS_IN Location:Distribution Centers\n - Organization:Amazon INVESTS_IN Technology:Cloud\n - Organization:Amazon INVESTS_IN Product:Video Content\n - Organization:Amazon OPPORTUNITY Country:India\n - Organization:Amazon USES Technology:Elastic Block Storage (Ebs)\n - Organization:Federal Trade Commission REGULATES Organization:Amazon\n - Organization:International Consumer Protection And Enforcement Network SUPPORTS Organization:Amazon\n\nDocument end\n""]","Rivals target cost-conscious readers and compete with Amazon by pursuing an integrated focused cost leadership/differentiation strategy. They provide books that are not readily or commonly available at a less expensive price. They aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers.",reasoning,0.9999999999,0.25,0.0,0.9854858394471804,0.7730167298767534 +How do rivals target cost-conscious readers and compete with Amazon?,graph+vector,"Rivals targeting cost-conscious readers and competing with Amazon often employ strategies like cost leadership and differentiation. For instance, Barnes and Noble, a major competitor, uses an integrated focused cost leadership/differentiation strategy. They target price-sensitive consumers by offering books not commonly available at a lower price. This approach allows them to compete effectively with Amazon in the book industry by appealing to cost-conscious readers while providing unique offerings.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: Text Content:\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Sales_Taxes\n:Smartphone_App\nActivity:Online Shopping\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\nTechnology:Internet\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Shivam Dube PLAYER Country:India\nPerson:Tristan Landrecht\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: Text Content:\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Sales_Taxes\n:Smartphone_App\nActivity:Online Shopping\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\nTechnology:Internet\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Shivam Dube PLAYER Country:India\nPerson:Tristan Landrecht\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon 1.pdf\nContent: MEMBER Course:Bus 478\nPerson:Virat Kohli PLAYER Country:India\nPerson:Yashasvi Jaiswal PLAYER Country:India\nTechnology:Internet SUPPORTS Activity:Online Shopping\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: MEMBER Course:Bus 478\nPerson:Virat Kohli PLAYER Country:India\nPerson:Yashasvi Jaiswal PLAYER Country:India\nTechnology:Internet SUPPORTS Activity:Online Shopping\nDocument end\n']","Rivals target cost-conscious readers and compete with Amazon by pursuing an integrated focused cost leadership/differentiation strategy. They provide books that are not readily or commonly available at a less expensive price. They aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers.",reasoning,0.9999999999,1.0,1.0,0.9743047031882105,0.6700624112374851 +How do rivals target cost-conscious readers and compete with Amazon?,graph+vector+fulltext,"Rivals target cost-conscious readers and compete with Amazon by employing strategies like integrated focused cost leadership/differentiation. They aim to offer products not commonly available at lower prices, appealing to price-sensitive consumers. Competitors focus on increasing profitability, gaining market share, and providing a wide variety of products through competitive pricing, cost leadership, and differentiation strategies to challenge Amazon's market dominance.","['Document start\nThis Document belongs to the source About Amazon 1.pdf\nContent: Text Content:\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Sales_Taxes\n:Smartphone_App\nActivity:Online Shopping\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\nTechnology:Internet\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Shivam Dube PLAYER Country:India\nPerson:Tristan Landrecht\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: Text Content:\n\t\r \xa0 1 Company Background When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble. As time went on, Amazon became widely known as the place to shop for books, and the self proclaimed: “world’s largest bookstore”. As time progressed, so did Amazon’s business strategy. Amazon transformed their corporate-level strategy into a mergers and acquisitions approach and did this with great success. Amazon’s goal today is to be a place a customer can go to purchase anything online. Amazon has transformed from a garage-based bookstore into a $48 billion dollar retail machine. They have been able to do this thanks to the power of technological progress. Computational power, bandwidth and data \n----\n both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. 3 Assumptions: Competitors believe that the demand for online shopping will continue to grow as consumers seek for more convenient and efficient ways of shopping. 4 Capabilities: Competitors offer similar products as Amazon either at a lower price or accompanied with differentiated services. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers. Current Situations & Challenges Amazon uses huge amount of data storage to improve customer service. However, Amazon’s Elastic Block Storage (EBS) service has been down several times in 2012 due to an \n----\n\t\r \xa0 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a variety of products, high-quality service security, and E-commerce services. Barnes and Noble, America’s largest book retailer operating both online and physical retail businesses, competes intensively with Amazon for the market share in the book industry. It pursues an integrated focused cost leadership/differentiation strategy to target price-sensitive consumers by providing books not readily or commonly available at a less expensive price. The competitors’ analysis can be summarized as below: 1 Future objectives: Competitors want to compete for a good strategic position and become the market leader in both e-commerce and physical commerce. 2 Current strategy: Competitors aim to increase profitability,\n----\n\t\r \xa0 5 information online. The fact that Amazon is able to reduce their overhead costs by not having retail locations allows them to achieve these low prices, enabling them to compete in the industry. Threat of Substitute Products The threat of substitutes for Amazon is high. The only unique characteristic Amazon has is the patented technology (such as 1-Click Ordering), which differentiates them from other possible substitutes. However, there are many alternatives providing the same products and services, which could reduce Amazon’s competitive advantage. Therefore, Amazon does not have absolute competitive advantage on their product offerings, but they definitely have the advantage when it comes to the quality of customer service and convenience provided. Rivalry Among Competing Firms Rivalry among competing firms is high. There are a vast number of search engines on the Internet which are able to influence customers decisions when searching for the best online retailer. There is also an increasing number of dot\n----\n\t\r \xa0 2 been occurring is that many consumers are changing their spending habits toward finding “bargain goods”. Amazon has been able to benefit from this greatly thanks to their ability to offer affordable goods quickly and easily to the general public. Sociocultural Online shopping has grown dramatically in popularity over recent years. E-commerce is convenient since there are no geographic restrictions and consumers can have access to a selection of goods wherever and whenever they want. Moreover, there is an unlimited selection of merchandise for customers to review and compare. These advantages shift customers’ shopping behavior from retail stores to online shopping. According to a survey of online shoppers: 48 percent of respondents shopped online in the past 12 months, 66 percent preferred web retailers, and 73 percent completed nearly half of their shopping online. The increasing popularity of online shopping is providing a foundation for Amazon to exploit their core competencies. Global With the advances in\n----\n content and distribution centers, it is difficult to predict when the benefits from these investments will be realized. Amazon has stopped growing for a while and their margin has been constant for several years. The company needs a margin expansion in order to prevent the company’s share price from dropping. Future Outlook Overall, there are remarkable challenges for Amazon to yet overcome. If they are able to swiftly react they will be able to maintain their competitive advantages through harnessing their core competencies. Continued success in the emerging markets will ensure that Amazon has a bright and better tomorrow. \n----\n providing a foundation for Amazon to exploit their core competencies. Global With the advances in modern tech support and web security, people are getting more and more willing to make purchases online. As the economies of emerging markets are rising dramatically, people in those countries with increasing purchasing power are spending more on online shopping. Services such as Amazon are able to exploit this opportunity by offering consumers goods which are not readily available in local markets. While firms expand internationally, it is critical to take into account of the differences in consumer preferences. Technological The Internet is an excellent source of data that provides the most timely available information that captures the shift in consumer preferences and trends. As technology has been rapidly advancing, businesses have been influenced by technological innovations. For example, \n----\n influence customers decisions when searching for the best online retailer. There is also an increasing number of dot-com retailers due to the relatively low start-up costs of the business. Competitor Analysis As the fastest-growing, multinational e-commerce retailer in America, Amazon has an international presence over various categories and faces an intense competition. Based on the similarity in the breadth of products, geographic market coverage, and scope of business, three major competitors are identified: eBay, Barnes and Noble, and Wal-Mart. Wal-Mart, as the world’s largest retail chain, utilizes a cost leadership strategy with low cost management in value chain to market its products at the lowest price through both e- commerce and physical stores. \n----\n\t\r \xa0 4 should also exploit opportunities from emerging countries, such as China and India, which have large populations and growing disposable income. Based on a global survey of online shoppers, people in China engaged in online shopping 8.4 times more than those in any other markets on a monthly basis. Thanks to the network of distribution services and the power of E-Commerce, Amazon is in a position to utilize its core competencies in order to capture the global market. Industry Analysis Threat of New Entrants The threat of new entrants is considered to be low. It is easy for companies to start-up in this industry due to the relatively low capital investment costs. However, to achieve the position in the industry that Amazon holds it would require huge investment in infrastructure and inventory. It is also hard for new entrants to gain customer loyalty since the existing major competitors, such as Amazon, have established a loyal customer base. \n----\n to do this thanks to the power of technological progress. Computational power, bandwidth and data storage technologies all have improved and have become relatively cheaper over time. In the present day, Amazon sells products in over forty categories. They have everything from books to electronics, to groceries. Today Amazon is a logistics platform, a search engine, an Internet advertising platform, as well as fulfilling roles as an e-commerce and IT platform. The key areas of focus for Amazon are low prices, convenience, selection, and availability. External Analysis General Environment Economic Since the start of 2008, the global economy has been in a recession. The World Bank reduced each country’s expected GDP growth for the year of 2013. The low GDP growth and high unemployment rate have reduced people’s wealth and purchasing power of goods. When the market tanked, many people chose to migrate their shopping onto an online platform. In 2011, online\n----\nEntities:\n:Cost Leadership\n:Differentiation\n:Global_Market\n:Integrated Focused Cost Leadership/Differentiation\n:Online_Sales_Taxes\n:Smartphone_App\nActivity:Online Shopping\nAmount:$48 Billion\nCompany:Amazon.Com (Founded in 1993 by Jeff Benzos, initially an online bookstore, now a $48 billion retail machine selling products in over forty categories.)\nCountry:Afghanistan\nCountry:China (Emerging country with large population and growing disposable income.)\nCountry:India (Emerging country with large population and growing disposable income.)\nCourse:Bus 478 (Seminar on Business Strategy)\nDate:1993\nEvent:Dot-Com Bubble\nLocation:Distribution Centers\nLocation:U.S. East Data Center\nOrganization:Amazon (Fastest-growing, multinational e-commerce retailer in America with international presence.)\nOrganization:Barnes And Noble (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Ebay (Major competitor of Amazon based on product breadth, geographic market coverage, and scope of business.)\nOrganization:Florida Panthers (Reigning league champions, winning the 2024 Stanley Cup Finals.)\nOrganization:Wal-Mart (World’s largest retail chain utilizing a cost leadership strategy with low cost management in value chain.)\nPerson:Jae Kim\nPerson:Jeff Benzos (Founder of Amazon.com)\nPerson:Jessica Zhang\nPerson:Jin Can Chen\nPerson:John Chen\nPerson:Mir Osman Ali Khan (The seventh Nizam who signed an instrument of accession, joining India.)\nPerson:Nizam (Ruler of Hyderabad State from 1724 to 1948, initially a viceroy of the Mughal empire in the Deccan.)\nPerson:Rinku Singh\nPerson:Rohit Sharma\nPerson:Sanju Samson\nPerson:Shivam Dube\nPerson:Tristan Landrecht\nPerson:Virat Kohli\nPerson:Yashasvi Jaiswal\nProduct:Kindle\nProduct:Video Content\nTechnology:1-Click Ordering\nTechnology:Cloud\nTechnology:Elastic Block Storage (Ebs)\nTechnology:Internet\n----\nRelationships:\nCompany:Amazon.Com FOUNDED Date:1993\nCompany:Amazon.Com FOUNDER Person:Jeff Benzos\nCompany:Amazon.Com GROWTH_MOMENTUM Event:Dot-Com Bubble\nCompany:Amazon.Com VALUATION Amount:$48 Billion\nCountry:India MATCH Country:Afghanistan\nCourse:Bus 478 GROUP_MEMBER Person:Jae Kim\nCourse:Bus 478 GROUP_MEMBER Person:Jessica Zhang\nCourse:Bus 478 GROUP_MEMBER Person:Jin Can Chen\nCourse:Bus 478 GROUP_MEMBER Person:John Chen\nCourse:Bus 478 GROUP_MEMBER Person:Tristan Landrecht\nCourse:Bus 478 PROJECT Company:Amazon.Com\nOrganization:Amazon CAPTURES :Global_Market\nOrganization:Amazon COMPETES_WITH Organization:Barnes And Noble\nOrganization:Amazon COMPETES_WITH Organization:Ebay\nOrganization:Amazon COMPETES_WITH Organization:Wal-Mart\nOrganization:Amazon COMPETITOR Organization:Barnes And Noble\nOrganization:Amazon COMPETITOR Organization:Ebay\nOrganization:Amazon COMPETITOR Organization:Wal-Mart\nOrganization:Amazon DISCLOSES :Online_Sales_Taxes\nOrganization:Amazon INVESTS_IN Location:Distribution Centers\nOrganization:Amazon INVESTS_IN Product:Kindle\nOrganization:Amazon INVESTS_IN Product:Video Content\nOrganization:Amazon INVESTS_IN Technology:Cloud\nOrganization:Amazon LOCATED_AT Location:U.S. East Data Center\nOrganization:Amazon OPPORTUNITY Country:China\nOrganization:Amazon RELEASED :Smartphone_App\nOrganization:Amazon USES Technology:1-Click Ordering\nOrganization:Amazon USES Technology:Elastic Block Storage (Ebs)\nOrganization:Barnes And Noble COMPETES_WITH Organization:Amazon\nOrganization:Barnes And Noble USES :Integrated Focused Cost Leadership/Differentiation\nOrganization:Ebay COMPETES_WITH Organization:Amazon\nOrganization:Ebay USES :Cost Leadership\nOrganization:Ebay USES :Differentiation\nOrganization:Florida Panthers ESTABLISHED Date:1993\nOrganization:Wal-Mart USES :Cost Leadership\nPerson:Jae Kim MEMBER Course:Bus 478\nPerson:Jessica Zhang MEMBER Course:Bus 478\nPerson:Jin Can Chen MEMBER Course:Bus 478\nPerson:John Chen MEMBER Course:Bus 478\nPerson:Mir Osman Ali Khan SIGNED_ACCESSION Country:India\nPerson:Nizam JOINED Country:India\nPerson:Rinku Singh PLAYER Country:India\nPerson:Rohit Sharma PLAYER Country:India\nPerson:Sanju Samson PLAYER Country:India\nPerson:Shivam Dube PLAYER Country:India\nPerson:Tristan Landrecht\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon 1.pdf\nContent: MEMBER Course:Bus 478\nPerson:Virat Kohli PLAYER Country:India\nPerson:Yashasvi Jaiswal PLAYER Country:India\nTechnology:Internet SUPPORTS Activity:Online Shopping\nDocument end\n\n\nDocument start\nThis Document belongs to the source About Amazon.pdf\nContent: MEMBER Course:Bus 478\nPerson:Virat Kohli PLAYER Country:India\nPerson:Yashasvi Jaiswal PLAYER Country:India\nTechnology:Internet SUPPORTS Activity:Online Shopping\nDocument end\n']","Rivals target cost-conscious readers and compete with Amazon by pursuing an integrated focused cost leadership/differentiation strategy. They provide books that are not readily or commonly available at a less expensive price. They aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers.",reasoning,0.9999999999,1.0,1.0,0.9332925514808473,0.8453744755969357 +How do rivals target cost-conscious readers and compete with Amazon?,global search+vector+fulltext,"Rivals target cost-conscious readers and compete with Amazon by employing strategies such as cost leadership and differentiation. For example, eBay utilizes both cost leadership and differentiation strategies to attract price-sensitive customers. Barnes and Noble integrates a focused cost leadership with differentiation approach to cater to readers looking for quality products at competitive prices. Wal-Mart, as the world's largest retail chain, focuses on cost leadership to offer affordable options to cost-conscious readers. These strategies help rivals position themselves effectively in the market and compete with Amazon's offerings.","[""Document start\nThis Document belongs to the source unknown\nContent: Amazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offers a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, being regulated by the Federal Trade Commission and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nAmazon is a rapidly growing multinational e-commerce retailer based in America with a significant international presence. It faces competition from major organizations such as eBay, Barnes and Noble, and Wal-Mart. eBay and Barnes and Noble are noted for their product breadth and geographic market coverage, while Wal-Mart is recognized as the world's largest retail chain, employing a cost leadership strategy.\n\nAmazon competes with eBay, which utilizes both cost leadership and differentiation strategies. Barnes and Noble also competes with Amazon, employing an integrated focused cost leadership/differentiation strategy. Wal-Mart, another competitor, uses a cost leadership approach.\n\nAmazon is actively investing in various technologies and products, including video content, cloud services, and its Kindle product. It utilizes technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations. The company has also released a smartphone app and is located at the U.S. East Data Center.\n\nAmazon sees opportunities in emerging markets like China, which has a large population and growing disposable income. It is focused on capturing the global market and has invested in distribution centers to support this goal. The company discloses information about online sales taxes and is regulated by the Federal Trade Commission. Additionally, it receives support from the International Consumer Protection and Enforcement Network.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offers a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, regulated by the Federal Trade Commission, and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nAmazon, a leading American multinational e-commerce retailer, is experiencing rapid growth and has established a significant international presence. It competes with major organizations such as eBay, Barnes and Noble, and Wal-Mart. Each competitor employs distinct strategies: eBay uses both cost leadership and differentiation, Barnes and Noble integrates focused cost leadership with differentiation, and Wal-Mart, the world's largest retail chain, focuses on cost leadership.\n\nAmazon is heavily investing in various technologies and products, including video content, cloud services, and its Kindle product. It leverages technologies like Elastic Block Storage (EBS) and 1-Click Ordering to enhance its operations and has developed a smartphone app. The company is strategically located at the U.S. East Data Center and is actively pursuing opportunities in emerging markets like China, which offer a large population and increasing disposable income. To support its global market capture, Amazon has invested in distribution centers and is transparent about online sales taxes, regulated by the Federal Trade Commission, and supported by the International Consumer Protection and Enforcement Network.\n\nOnline shopping, a central activity in e-commerce, is particularly popular among Generation X and Generation Y, with Baby Boomers participating less. The growth of online shopping is driven by the Internet, modern tech support, web security, and smartphones, which enhance the shopping experience. Online payment methods further increase convenience and efficiency. E-commerce acts as a catalyst for this growth, with emerging markets showing significant potential. Looking ahead, 3D virtual technology is anticipated to transform the online shopping experience, offering new dimensions to consumer engagement.\n----\nThe community consists of a group of individuals, Jin Can Chen, Jae Kim, Jessica Zhang, John Chen, and Tristan Landrecht, who are enrolled in Bus 478, a seminar focused on business strategy. This course involves a collaborative or team-based approach, suggesting that these members work closely together on projects or discussions related to business strategy. Additionally, the community is linked to Amazon.com, a company founded in 1993 by Jeff Benzos. Originally an online bookstore, Amazon has evolved into a vast retail enterprise valued at $48 billion, offering a wide range of products across more than forty categories. The company saw substantial growth during the Dot-Com Bubble, with Jeff Benzos playing a crucial role in its expansion and success. This connection to Amazon may indicate that the course or group discussions could involve case studies or strategic analyses of Amazon's business model and growth trajectory.\n----\nAmazon.com, founded in 1993 by Jeff Benzos, initially started as an online bookstore. Over the years, it has grown into a massive retail enterprise valued at $48 billion, offering products across more than forty categories. The company experienced significant growth momentum during the Dot-Com Bubble. Jeff Benzos, the founder, played a pivotal role in its development and expansion.\n----\nThe community consists of individuals and entities connected through educational and business endeavors. Jin Can Chen, Jae Kim, Jessica Zhang, John Chen, and Tristan Landrecht are all participants in Bus 478, a seminar focused on business strategy, which emphasizes teamwork and collaboration. This educational setting likely fosters skills relevant to business growth and strategy, akin to those demonstrated by Amazon.com. Founded in 1993 by Jeff Benzos, Amazon began as an online bookstore and evolved into a vast retail empire valued at $48 billion, offering a diverse range of products across more than forty categories. The company's significant expansion, particularly during the Dot-Com Bubble, highlights the importance of strategic business planning and leadership, as exemplified by Benzos' pivotal role in its success. This connection between the educational focus of Bus 478 and the business strategies employed by Amazon underscores the relevance of strategic thinking in both academic and real-world business contexts.\n----\nThe community consists of individuals and entities connected through educational and business endeavors. Jin Can Chen, Jae Kim, Jessica Zhang, John Chen, and Tristan Landrecht are all participants in Bus 478, a seminar focused on business strategy, which emphasizes teamwork and collaboration. This educational setting likely fosters skills relevant to business growth and strategy, akin to those demonstrated by Amazon.com. Founded in 1993 by Jeff Benzos, Amazon began as an online bookstore and evolved into a vast retail empire valued at $48 billion, offering a diverse range of products across more than forty categories. The company's significant expansion, particularly during the Dot-Com Bubble, highlights the importance of strategic business planning and leadership, as exemplified by Benzos' pivotal role in its success. This connection between the educational focus of Bus 478 and the business strategies employed by Amazon underscores the relevance of strategic thinking in both academic and real-world business contexts.\n----\nGeneration X and Y, recognized for their proficiency with technology, are demographic cohorts that frequently participate in online shopping activities. These groups are characterized by their comfort and familiarity with digital platforms, which facilitates their engagement in e-commerce. Their technological adeptness not only influences their purchasing habits but also reflects broader trends in consumer behavior, where digital literacy plays a crucial role in shaping market dynamics. As active participants in the online marketplace, Generation X and Y contribute significantly to the growth and evolution of e-commerce, highlighting the importance of targeting these demographics in digital marketing strategies.\n----\nGeneration X and Y, recognized for their proficiency with technology, are demographic cohorts that frequently participate in online shopping activities. These groups are characterized by their comfort and familiarity with digital platforms, which facilitates their engagement in e-commerce. Their technological adeptness not only influences their purchasing habits but also reflects broader trends in consumer behavior, where digital literacy plays a crucial role in shaping how and where people choose to shop.\nDocument end\n""]","Rivals target cost-conscious readers and compete with Amazon by pursuing an integrated focused cost leadership/differentiation strategy. They provide books that are not readily or commonly available at a less expensive price. They aim to increase profitability, gain market share, and provide a wide variety of products to compete against Amazon through utilizing competitive pricing, cost leadership, and differentiation strategies. Some of them have an international presence with stable financial performance, enabling them to form global strategic alliances to increase their market base of customers.",reasoning,0.9999999999,0.5,0.5454545454545454,0.9332912351327914,0.48836403633073866 diff --git a/experiments/modes_comparison_RAGAS.ipynb b/experiments/modes_comparison_RAGAS.ipynb new file mode 100644 index 000000000..bcc604319 --- /dev/null +++ b/experiments/modes_comparison_RAGAS.ipynb @@ -0,0 +1,3442 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Objective : To evaluate different retrievers used in llm-graph-builder application using RAGAS library" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#Installation \n", + "#Other packages can be installed from requirement.txt\n", + "\n", + "!pip install ragas==0.1.14 seaborn" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Pre requisites to run this notebook\n", + "A pdf file to be kept in files folder and same has to be uploaded in llm-graph-builder application" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/workspaces/llm-graph-builder/backend/src/shared/common_fn.py:89: LangChainDeprecationWarning: The class `HuggingFaceEmbeddings` was deprecated in LangChain 0.2.2 and will be removed in 1.0. An updated version of the class exists in the langchain-huggingface package and should be used instead. To use it run `pip install -U langchain-huggingface` and import as `from langchain_huggingface import HuggingFaceEmbeddings`.\n", + " embeddings = SentenceTransformerEmbeddings(\n", + "/opt/conda/envs/myenv310/lib/python3.10/site-packages/sentence_transformers/cross_encoder/CrossEncoder.py:11: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", + " from tqdm.autonotebook import tqdm, trange\n" + ] + } + ], + "source": [ + "#importing all necessary packages\n", + "#keeping this notebook in experiements folder \n", + "import sys\n", + "import os\n", + "import pandas as pd\n", + "import numpy as np\n", + "import seaborn as sns\n", + "import matplotlib.pyplot as plt\n", + "from dotenv import load_dotenv\n", + "sys.path.append(os.path.abspath('../backend'))\n", + "from src.llm import get_llm\n", + "from src.QA_integration import QA_RAG, create_neo4j_chat_message_history,get_chat_mode_settings,get_neo4j_retriever,create_document_retriever_chain,retrieve_documents,format_documents,clear_chat_history\n", + "from langchain_core.messages import HumanMessage\n", + "from langchain_community.graphs import Neo4jGraph\n", + "from langchain_community.document_loaders import DirectoryLoader\n", + "from langchain_openai import ChatOpenAI, OpenAIEmbeddings\n", + "from datasets import Dataset, Features, Sequence, Value\n", + "from ragas.testset.generator import TestsetGenerator\n", + "from ragas.testset.evolutions import simple, reasoning, multi_context" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Python version : 3.10.14 (main, May 6 2024, 19:42:50) [GCC 11.2.0]\n", + "Ragas version : 0.1.14\n", + "langchain version : 0.2.14\n" + ] + } + ], + "source": [ + "#Check version of libraries installed as it is crucial to have specific version to run the code in codespace\n", + "### Python version : 3.10.14\n", + "### Ragas version : 0.1.14\n", + "### langchain version : 0.2.14\n", + "import sys\n", + "import ragas\n", + "import langchain\n", + "print(\"Python version : \",sys.version)\n", + "print(\"Ragas version : \", ragas.__version__)\n", + "print(\"langchain version : \", langchain.__version__)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "#Loading environmental variables\n", + "load_dotenv()\n", + "\n", + "OPENAI_API_KEY = os.getenv(\"OPENAI_API_KEY\")\n", + "uri = os.getenv(\"NEO4J_URI\")\n", + "userName = os.getenv(\"NEO4J_USERNAME\")\n", + "password = os.getenv(\"NEO4J_PASSWORD\")\n", + "database = os.getenv(\"NEO4J_DATABASE\")" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/opt/conda/envs/myenv310/lib/python3.10/site-packages/pypdf/_crypt_providers/_cryptography.py:32: CryptographyDeprecationWarning: ARC4 has been moved to cryptography.hazmat.decrepit.ciphers.algorithms.ARC4 and will be removed from this module in 48.0.0.\n", + " from cryptography.hazmat.primitives.ciphers.algorithms import AES, ARC4\n" + ] + } + ], + "source": [ + "#Loading file kept in files folder through langchain loader\n", + "# Here we are using \"About Amazon.pdf\"\n", + "loader = DirectoryLoader(\"files\")\n", + "documents = loader.load() " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If above code gives error in codespace then run following commands in terminal \n", + "\n", + "sudo apt-get update\n", + "\n", + "sudo apt-get install -y libgl1-mesa-glx \n", + "\n", + "pip install opencv-python\n", + "\n", + "pip install typing \n", + "\n", + "then restart the kernel" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING:ragas.testset.docstore:Filename and doc_id are the same for all nodes.\n", + "Generating: 100%|██████████| 15/15 [03:48<00:00, 15.21s/it]\n" + ] + } + ], + "source": [ + "#Generating synthetic test set through RAGAS library\n", + "\n", + "generator_llm = ChatOpenAI(model=\"gpt-4\")\n", + "critic_llm = ChatOpenAI(model=\"gpt-4\")\n", + "embeddings = OpenAIEmbeddings()\n", + "\n", + "generator = TestsetGenerator.from_langchain(\n", + " generator_llm,\n", + " critic_llm,\n", + " embeddings\n", + ")\n", + "\n", + "try: \n", + " testset = generator.generate_with_langchain_docs(documents, test_size=15, distributions={simple:0.3, reasoning: 0.3, multi_context: 0.4})\n", + "except Exception as e:\n", + " print(\"Error: \",e)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
    \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
    questioncontextsground_truthevolution_typemetadataepisode_done
    0What issues did Amazon's Elastic Block Storage...[�s largest book retailer operating both onlin...In 2012, Amazon's Elastic Block Storage (EBS) ...simple[{'source': 'files/About Amazon.pdf'}]True
    1How does the integrated focused cost leadershi...[�s largest book retailer operating both onlin...The integrated focused cost leadership/differe...simple[{'source': 'files/About Amazon.pdf'}]True
    2What is the competitive strategy of Barnes and...[ online advertising and the security of consu...The answer to given question is not present in...simple[{'source': 'files/About Amazon.pdf'}]True
    3Why should online retailers like Amazon be car...[ online advertising and the security of consu...Online retailers like Amazon should be careful...simple[{'source': 'files/About Amazon.pdf'}]True
    4How threatening are substitute products to Ama...[ online advertising and the security of consu...The threat of substitutes for Amazon is high. ...reasoning[{'source': 'files/About Amazon.pdf'}]True
    \n", + "
    " + ], + "text/plain": [ + " question \\\n", + "0 What issues did Amazon's Elastic Block Storage... \n", + "1 How does the integrated focused cost leadershi... \n", + "2 What is the competitive strategy of Barnes and... \n", + "3 Why should online retailers like Amazon be car... \n", + "4 How threatening are substitute products to Ama... \n", + "\n", + " contexts \\\n", + "0 [�s largest book retailer operating both onlin... \n", + "1 [�s largest book retailer operating both onlin... \n", + "2 [ online advertising and the security of consu... \n", + "3 [ online advertising and the security of consu... \n", + "4 [ online advertising and the security of consu... \n", + "\n", + " ground_truth evolution_type \\\n", + "0 In 2012, Amazon's Elastic Block Storage (EBS) ... simple \n", + "1 The integrated focused cost leadership/differe... simple \n", + "2 The answer to given question is not present in... simple \n", + "3 Online retailers like Amazon should be careful... simple \n", + "4 The threat of substitutes for Amazon is high. ... reasoning \n", + "\n", + " metadata episode_done \n", + "0 [{'source': 'files/About Amazon.pdf'}] True \n", + "1 [{'source': 'files/About Amazon.pdf'}] True \n", + "2 [{'source': 'files/About Amazon.pdf'}] True \n", + "3 [{'source': 'files/About Amazon.pdf'}] True \n", + "4 [{'source': 'files/About Amazon.pdf'}] True " + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#Creating dataframe from generated test set\n", + "\n", + "generated_testdf = testset.to_pandas()\n", + "generated_testdf.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[\"What issues did Amazon's Elastic Block Storage (EBS) service face in 2012 and how did it affect the company?\",\n", + " 'How does the integrated focused cost leadership/differentiation strategy help competitors compete with Amazon in the book industry?',\n", + " 'What is the competitive strategy of Barnes and Noble in the e-commerce industry?',\n", + " 'Why should online retailers like Amazon be careful about disclosing online sales taxes in their advertisements?',\n", + " \"How threatening are substitute products to Amazon's patented tech and customer service?\",\n", + " \"What was the 2012 issue with Amazon's EBS and its proposed fix?\",\n", + " \"What strategy led to Amazon's growth from a small bookstore to a $48B retail giant?\",\n", + " 'What strategic shift helped Amazon evolve from a small bookstore to a $48B retail giant?',\n", + " \"How has Amazon's M&A strategy, transitioning from an online bookstore to a multi-category platform, been shaped by competition?\",\n", + " \"What strategies are Amazon's book competitors using for market share and how does it compare to Amazon's?\",\n", + " 'What methods does ICPEN use for cross-border online consumer issues and its effect on retailers like Amazon?',\n", + " \"What strategies do Amazon's book competitors use to attract price-sensitive customers and grow market share, leveraging online shopping and unique, cheap books?\",\n", + " \"What strategies are Amazon's book rivals using for price-sensitive customers and market growth, and its impact on Amazon's long-term investment focus?\",\n", + " \"What were the 2012 issues with Amazon's EBS at the U.S. East center and their impact on customer service and future investments?\",\n", + " 'How do rivals target cost-conscious readers and compete with Amazon?']" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "generated_testdf['question'].to_list()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Questions are of following types\n", + "\n", + "Simple : Straight forward question from the context\n", + "\n", + "Reasoning: Rewrite the question in a way that enhances the need for reasoning to answer it effectively.\n", + "\n", + "Multi-Context: Rephrase the question in a manner that necessitates information from multiple related sections or chunks to formulate an answer." + ] + }, + { + "cell_type": "code", + "execution_count": 113, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "evolution_type\n", + "multi_context 6\n", + "reasoning 5\n", + "simple 4\n", + "Name: count, dtype: int64" + ] + }, + "execution_count": 113, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "generated_testdf['evolution_type'].value_counts()" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "#Optional - Saving generated testset for further use\n", + "\n", + "generated_testdf.to_csv(\"RAGAS_testset.csv\",index= False)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "#Optional if you are re running code you can start from here\n", + "#generated_testdf = pd.read_csv(\"RAGAS_testset.csv\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Now we will call our QnA bot to answer same questions that are generated through test set" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "def create_graph_database_connection(uri, userName, password, database):\n", + " enable_user_agent = os.environ.get(\"ENABLE_USER_AGENT\", \"False\").lower() in (\"true\", \"1\", \"yes\")\n", + " if enable_user_agent:\n", + " graph = Neo4jGraph(url=uri, database=database, username=userName, password=password, refresh_schema=False, sanitize=True,driver_config={'user_agent':os.environ.get('NEO4J_USER_AGENT')}) \n", + " else:\n", + " graph = Neo4jGraph(url=uri, database=database, username=userName, password=password, refresh_schema=False, sanitize=True) \n", + " return graph" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "#Graph connection\n", + "graph = create_graph_database_connection(uri, userName, password, database)\n", + "\n", + "#Chat modes\n", + "CHAT_VECTOR_MODE = \"vector\"\n", + "CHAT_FULLTEXT_MODE = \"fulltext\"\n", + "CHAT_ENTITY_VECTOR_MODE = \"entity search+vector\"\n", + "CHAT_VECTOR_GRAPH_MODE = \"graph+vector\"\n", + "CHAT_VECTOR_GRAPH_FULLTEXT_MODE = \"graph+vector+fulltext\"\n", + "CHAT_GLOBAL_VECTOR_FULLTEXT_MODE = \"global search+vector+fulltext\"\n", + "\n", + "Modes = [CHAT_VECTOR_MODE,CHAT_FULLTEXT_MODE,CHAT_ENTITY_VECTOR_MODE,CHAT_VECTOR_GRAPH_MODE,CHAT_VECTOR_GRAPH_FULLTEXT_MODE,CHAT_GLOBAL_VECTOR_FULLTEXT_MODE]\n" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[\"What issues did Amazon's Elastic Block Storage (EBS) service face in 2012 and how did it affect the company?\",\n", + " 'How does the integrated focused cost leadership strategy help competitors compete with Amazon in the book industry?',\n", + " 'What is the competitive strategy of Barnes and Noble in the e-commerce industry?',\n", + " 'Why should online retailers like Amazon be careful about disclosing online sales taxes in their advertisements?',\n", + " \"How threatening are substitute products to Amazon's patented tech and customer service?\",\n", + " \"What was the 2012 issue with Amazon's EBS and its proposed fix?\",\n", + " \"What strategy led to Amazon's growth from a small bookstore to a $48B retail giant?\",\n", + " 'What strategic shift helped Amazon evolve from a small bookstore to a $48B retail giant?',\n", + " \"How has Amazon's M and A strategy, transitioning from an online bookstore to a multi-category platform, been shaped by competition?\",\n", + " \"What strategies are Amazon's book competitors using for market share and how does it compare to Amazon's?\",\n", + " 'What methods does ICPEN use for cross-border online consumer issues and its effect on retailers like Amazon?',\n", + " \"What strategies do Amazon's book competitors use to attract price-sensitive customers and grow market share, leveraging online shopping and unique, cheap books?\",\n", + " \"What strategies are Amazon's book rivals using for price-sensitive customers and market growth, and its impact on Amazon's long-term investment focus?\",\n", + " \"What were the 2012 issues with Amazon's EBS at the U.S. East center and their impact on customer service and future investments?\",\n", + " 'How do rivals target cost-conscious readers and compete with Amazon?']" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#Creating list of questions from generated testset\n", + "Questions = generated_testdf['question'].to_list()\n", + "Questions" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [], + "source": [ + "def fetch_context(mode,session_id,question):\n", + " history = create_neo4j_chat_message_history(graph, session_id)\n", + " messages = history.messages\n", + " user_question = HumanMessage(content=question)\n", + " messages.append(user_question)\n", + " model = 'openai-gpt-3.5'\n", + " document_names = '[]'\n", + " llm, model_name = get_llm(model=model)\n", + " chat_mode_settings = get_chat_mode_settings(mode=mode)\n", + " retriever = get_neo4j_retriever(graph=graph, chat_mode_settings=chat_mode_settings, document_names=document_names)\n", + " doc_retriever = create_document_retriever_chain(llm, retriever)\n", + " docs = retrieve_documents(doc_retriever, messages) \n", + " context = format_documents(docs, model)\n", + " return context[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [], + "source": [ + "def test_chatbot_qna(uri, userName, password,database, model_name, mode, question):\n", + " \"\"\"Test chatbot QnA functionality for different modes.\"\"\"\n", + " print(question,mode)\n", + " session_id = int(Modes.index(mode)+1)\n", + " graph = create_graph_database_connection(uri, userName, password, database) \n", + " clear_chat_history(graph, session_id)\n", + " QA_n_RAG = QA_RAG(graph, model_name, question, '[]', session_id, mode)\n", + " generated_context = fetch_context(mode,session_id,question)\n", + " try:\n", + " assert len(QA_n_RAG['message']) > 20\n", + " return QA_n_RAG['message'],generated_context\n", + " except AssertionError as e:\n", + " print(\"Failed for mode : \",mode,\" session id :\",session_id, \"Error : \", e)\n", + " return QA_n_RAG" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [], + "source": [ + "def process_qna_pair(question, mode): \n", + " answer,generated_context = test_chatbot_qna(uri, userName, password,database,model_name='openai-gpt-3.5', mode=mode, question=question)\n", + " return question, mode, answer,generated_context" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#This cell may take few minutes based on no of question and modes\n", + "\n", + "results = []\n", + "results = [process_qna_pair(question, mode) for question in Questions for mode in Modes]" + ] + }, + { + "cell_type": "code", + "execution_count": 102, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
    \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
    questionmodeanswerapplication_context
    0What issues did Amazon's Elastic Block Storage...vectorAmazon's Elastic Block Storage (EBS) service f...Document start\\nThis Document belongs to the s...
    1What issues did Amazon's Elastic Block Storage...fulltextAmazon's Elastic Block Storage (EBS) service f...Document start\\nThis Document belongs to the s...
    2What issues did Amazon's Elastic Block Storage...entity search+vectorIn 2012, Amazon's Elastic Block Storage (EBS) ...Document start\\nThis Document belongs to the s...
    3What issues did Amazon's Elastic Block Storage...graph+vectorAmazon's Elastic Block Storage (EBS) service f...Document start\\nThis Document belongs to the s...
    4What issues did Amazon's Elastic Block Storage...graph+vector+fulltextAmazon's Elastic Block Storage (EBS) service f...Document start\\nThis Document belongs to the s...
    \n", + "
    " + ], + "text/plain": [ + " question mode \\\n", + "0 What issues did Amazon's Elastic Block Storage... vector \n", + "1 What issues did Amazon's Elastic Block Storage... fulltext \n", + "2 What issues did Amazon's Elastic Block Storage... entity search+vector \n", + "3 What issues did Amazon's Elastic Block Storage... graph+vector \n", + "4 What issues did Amazon's Elastic Block Storage... graph+vector+fulltext \n", + "\n", + " answer \\\n", + "0 Amazon's Elastic Block Storage (EBS) service f... \n", + "1 Amazon's Elastic Block Storage (EBS) service f... \n", + "2 In 2012, Amazon's Elastic Block Storage (EBS) ... \n", + "3 Amazon's Elastic Block Storage (EBS) service f... \n", + "4 Amazon's Elastic Block Storage (EBS) service f... \n", + "\n", + " application_context \n", + "0 Document start\\nThis Document belongs to the s... \n", + "1 Document start\\nThis Document belongs to the s... \n", + "2 Document start\\nThis Document belongs to the s... \n", + "3 Document start\\nThis Document belongs to the s... \n", + "4 Document start\\nThis Document belongs to the s... " + ] + }, + "execution_count": 102, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "retrieved_df = pd.DataFrame(results, columns=['question', 'mode', 'answer','application_context'])\n", + "retrieved_df.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Some of the asnwers given by bot are not appropriate" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
    \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
    questionmodeanswerapplication_context
    5What issues did Amazon's Elastic Block Storage...global search+vector+fulltextI don't have that specific information availab...Document start\\nThis Document belongs to the s...
    35What was the 2012 issue with Amazon's EBS and ...global search+vector+fulltextI don't have that information right now. Is th...Document start\\nThis Document belongs to the s...
    80What were the 2012 issues with Amazon's EBS at...entity search+vectorI don't have specific information regarding th...Document start\\nThis Document belongs to the s...
    83What were the 2012 issues with Amazon's EBS at...global search+vector+fulltextI don't have that information right now. Would...Document start\\nThis Document belongs to the s...
    \n", + "
    " + ], + "text/plain": [ + " question \\\n", + "5 What issues did Amazon's Elastic Block Storage... \n", + "35 What was the 2012 issue with Amazon's EBS and ... \n", + "80 What were the 2012 issues with Amazon's EBS at... \n", + "83 What were the 2012 issues with Amazon's EBS at... \n", + "\n", + " mode \\\n", + "5 global search+vector+fulltext \n", + "35 global search+vector+fulltext \n", + "80 entity search+vector \n", + "83 global search+vector+fulltext \n", + "\n", + " answer \\\n", + "5 I don't have that specific information availab... \n", + "35 I don't have that information right now. Is th... \n", + "80 I don't have specific information regarding th... \n", + "83 I don't have that information right now. Would... \n", + "\n", + " application_context \n", + "5 Document start\\nThis Document belongs to the s... \n", + "35 Document start\\nThis Document belongs to the s... \n", + "80 Document start\\nThis Document belongs to the s... \n", + "83 Document start\\nThis Document belongs to the s... " + ] + }, + "execution_count": 45, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "retrieved_df[retrieved_df['answer'].str.lower().str.startswith(\"i don't have\")]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Important : Above result shows certain questions were not answered by QnA bot.\n", + "\n", + "#Further analysis needs to be done here" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(86, 4)" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#We will only consider proper answers for analysis\n", + "\n", + "retrieved_df = retrieved_df[~retrieved_df['answer'].str.lower().str.startswith(\"i don't have\")]\n", + "retrieved_df.to_csv('chatbot_answers.csv', index=False)\n", + "retrieved_df.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [], + "source": [ + "#Optional if you are running code from here you can uncomment\n", + "\n", + "# retrieved_df = pd.read_csv(\"chatbot_answers.csv\")\n", + "# retrieved_df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [], + "source": [ + "generated_testdf = generated_testdf.rename(columns={'contexts':'RAGAS_context'})" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Generated test set columns : Index(['question', 'RAGAS_context', 'ground_truth', 'evolution_type',\n", + " 'metadata', 'episode_done'],\n", + " dtype='object')\n", + "QnA Bot Retrieved set columns: Index(['question', 'mode', 'answer', 'application_context'], dtype='object')\n" + ] + } + ], + "source": [ + "print(\"Generated test set columns : \",generated_testdf.columns)\n", + "print(\"QnA Bot Retrieved set columns: \",retrieved_df.columns)" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(86, 9)" + ] + }, + "execution_count": 56, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "final_df = pd.merge(retrieved_df,generated_testdf,on='question',how='left')\n", + "final_df.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": {}, + "outputs": [], + "source": [ + "#optional code if next cell is giving error as \"ValueError: Dataset feature \"contexts\" should be of type Sequence[string]\"ArithmeticError\n", + "\n", + "# final_df['contexts'] = final_df['contexts'].apply(lambda x:[x] if isinstance(x,str) else x)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### EVALUATION" + ] + }, + { + "cell_type": "code", + "execution_count": 73, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Dataset({\n", + " features: ['question', 'mode', 'answer', 'contexts', 'ground_truth', 'question_complexity'],\n", + " num_rows: 86\n", + "})" + ] + }, + "execution_count": 73, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#Creating dataset for evaluation\n", + "\n", + "data_samples = {\n", + " \n", + " 'question': final_df['question'].tolist(),\n", + " 'mode':final_df['mode'].tolist(),\n", + " 'answer': final_df['answer'].tolist(),\n", + " 'contexts': final_df['application_context'].tolist(),\n", + " 'ground_truth': final_df['ground_truth'].tolist(),\n", + " 'question_complexity' : final_df['evolution_type'].tolist()\n", + "}\n", + "features = Features({\n", + " 'question': Value('string'),\n", + " 'mode': Value('string'),\n", + " 'answer': Value('string'),\n", + " 'contexts': Value('string'), \n", + " 'ground_truth': Value('string'),\n", + " 'question_complexity': Value('string')\n", + "})\n", + "dataset = Dataset.from_dict(data_samples, features=features)\n", + "dataset" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#Converting context into list of strings as it is required in next step\n", + "\n", + "def preprocess_function(example):\n", + " example[\"contexts\"] = [example[\"contexts\"]]\n", + " return example\n", + "\n", + "dataset = dataset.map(preprocess_function)" + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Evaluating: 100%|██████████| 430/430 [03:23<00:00, 2.11it/s]\n" + ] + }, + { + "data": { + "text/html": [ + "
    \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
    questionmodeanswercontextsground_truthquestion_complexitycontext_precisioncontext_recallfaithfulnessanswer_relevancyanswer_correctness
    0What issues did Amazon's Elastic Block Storage...vectorAmazon's Elastic Block Storage (EBS) service f...[Document start\\nThis Document belongs to the ...In 2012, Amazon's Elastic Block Storage (EBS) ...simple1.01.00.7500.9240690.769896
    1What issues did Amazon's Elastic Block Storage...fulltextAmazon's Elastic Block Storage (EBS) service f...[Document start\\nThis Document belongs to the ...In 2012, Amazon's Elastic Block Storage (EBS) ...simple1.01.00.6250.9240260.797546
    2What issues did Amazon's Elastic Block Storage...entity search+vectorIn 2012, Amazon's Elastic Block Storage (EBS) ...[Document start\\nThis Document belongs to the ...In 2012, Amazon's Elastic Block Storage (EBS) ...simple0.00.00.0000.9507040.733410
    3What issues did Amazon's Elastic Block Storage...graph+vectorAmazon's Elastic Block Storage (EBS) service f...[Document start\\nThis Document belongs to the ...In 2012, Amazon's Elastic Block Storage (EBS) ...simple1.01.01.0000.9240690.845223
    4What issues did Amazon's Elastic Block Storage...graph+vector+fulltextAmazon's Elastic Block Storage (EBS) service f...[Document start\\nThis Document belongs to the ...In 2012, Amazon's Elastic Block Storage (EBS) ...simple1.01.01.0000.9266900.844968
    \n", + "
    " + ], + "text/plain": [ + " question mode \\\n", + "0 What issues did Amazon's Elastic Block Storage... vector \n", + "1 What issues did Amazon's Elastic Block Storage... fulltext \n", + "2 What issues did Amazon's Elastic Block Storage... entity search+vector \n", + "3 What issues did Amazon's Elastic Block Storage... graph+vector \n", + "4 What issues did Amazon's Elastic Block Storage... graph+vector+fulltext \n", + "\n", + " answer \\\n", + "0 Amazon's Elastic Block Storage (EBS) service f... \n", + "1 Amazon's Elastic Block Storage (EBS) service f... \n", + "2 In 2012, Amazon's Elastic Block Storage (EBS) ... \n", + "3 Amazon's Elastic Block Storage (EBS) service f... \n", + "4 Amazon's Elastic Block Storage (EBS) service f... \n", + "\n", + " contexts \\\n", + "0 [Document start\\nThis Document belongs to the ... \n", + "1 [Document start\\nThis Document belongs to the ... \n", + "2 [Document start\\nThis Document belongs to the ... \n", + "3 [Document start\\nThis Document belongs to the ... \n", + "4 [Document start\\nThis Document belongs to the ... \n", + "\n", + " ground_truth question_complexity \\\n", + "0 In 2012, Amazon's Elastic Block Storage (EBS) ... simple \n", + "1 In 2012, Amazon's Elastic Block Storage (EBS) ... simple \n", + "2 In 2012, Amazon's Elastic Block Storage (EBS) ... simple \n", + "3 In 2012, Amazon's Elastic Block Storage (EBS) ... simple \n", + "4 In 2012, Amazon's Elastic Block Storage (EBS) ... simple \n", + "\n", + " context_precision context_recall faithfulness answer_relevancy \\\n", + "0 1.0 1.0 0.750 0.924069 \n", + "1 1.0 1.0 0.625 0.924026 \n", + "2 0.0 0.0 0.000 0.950704 \n", + "3 1.0 1.0 1.000 0.924069 \n", + "4 1.0 1.0 1.000 0.926690 \n", + "\n", + " answer_correctness \n", + "0 0.769896 \n", + "1 0.797546 \n", + "2 0.733410 \n", + "3 0.845223 \n", + "4 0.844968 " + ] + }, + "execution_count": 76, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#Evaluating using RAGAS\n", + "\n", + "from ragas.metrics import (\n", + " answer_relevancy,\n", + " faithfulness,\n", + " context_recall,\n", + " context_precision,\n", + " answer_correctness\n", + ")\n", + "\n", + "from ragas import evaluate\n", + "\n", + "result = evaluate(\n", + " dataset,\n", + " metrics=[\n", + " context_precision,\n", + " context_recall,\n", + " faithfulness,\n", + " answer_relevancy,\n", + " answer_correctness,\n", + " ]\n", + ")\n", + "\n", + "eval_df = result.to_pandas()\n", + "eval_df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 83, + "metadata": {}, + "outputs": [], + "source": [ + "eval_df.to_csv(\"Final_Score.csv\",index= False)" + ] + }, + { + "cell_type": "code", + "execution_count": 84, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['question', 'mode', 'answer', 'contexts', 'ground_truth',\n", + " 'question_complexity', 'context_precision', 'context_recall',\n", + " 'faithfulness', 'answer_relevancy', 'answer_correctness'],\n", + " dtype='object')" + ] + }, + "execution_count": 84, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "eval_df.columns" + ] + }, + { + "cell_type": "code", + "execution_count": 85, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
    \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
    modequestion_complexitycontext_precisioncontext_recall...answer_relevancyanswer_correctness
    countmeanminmaxstdcountmeanmin...countmeanminmaxstdcountmeanminmaxstd
    0entity search+vectormulti_context50.8000000.01.00.44721450.5619050.142857...50.9442880.8978610.9700960.02812350.7424960.5234710.9922690.170004
    1entity search+vectorreasoning50.8000000.01.00.44721450.2500000.000000...50.9672520.9534660.9854860.01173550.8035360.5657110.9436290.147004
    2entity search+vectorsimple40.5000000.01.00.57735040.5000000.000000...40.9767750.9507041.0000000.02059640.5377660.1726750.7334100.251963
    3fulltextmulti_context60.8333330.01.00.40824860.9523810.714286...60.9398130.9308140.9553020.00961560.8033990.4373950.9955870.208676
    4fulltextreasoning51.0000001.01.00.00000051.0000001.000000...50.9549650.9348950.9742460.01438750.8533490.6190320.9967040.187401
    5fulltextsimple41.0000001.01.00.00000041.0000001.000000...40.9692420.9240261.0000000.03223140.6723180.1753730.9401640.339199
    6global search+vector+fulltextmulti_context50.8000000.01.00.44721450.5119050.142857...50.9340880.9003930.9677280.02959950.7355390.6095250.9091840.123181
    7global search+vector+fulltextreasoning40.5000000.01.00.57735040.1250000.000000...40.9537060.9332910.9667640.01433240.7278430.4883640.8461430.162029
    8global search+vector+fulltextsimple30.6666670.01.00.57735030.6666670.000000...30.9753290.9732300.9788110.00303730.3945940.1721250.6658700.250464
    9graph+vectormulti_context60.8333330.01.00.40824860.9523810.714286...60.9302910.8978610.9579430.02641060.7421800.4913980.9181700.188076
    10graph+vectorreasoning51.0000001.01.00.00000051.0000001.000000...50.7647480.0000000.9743050.42774550.8584120.6700620.9965560.137474
    11graph+vectorsimple41.0000001.01.00.00000041.0000001.000000...40.9446750.9144510.9894750.03357340.5594330.1749660.8452230.300916
    12graph+vector+fulltextmulti_context60.8333330.01.00.40824860.9523810.714286...60.9428060.9227840.9553020.01330660.7367840.4372160.9902460.237939
    13graph+vector+fulltextreasoning51.0000001.01.00.00000051.0000001.000000...50.9352750.8926180.9620120.02679650.7869990.4557120.9466830.190876
    14graph+vector+fulltextsimple41.0000001.01.00.00000041.0000001.000000...40.9723420.9266900.9999980.03235940.6436410.1750820.9343100.339174
    15vectormulti_context60.8333330.01.00.40824860.9107140.714286...60.9352970.9149590.9553380.01368860.8133150.5442150.9912020.156961
    16vectorreasoning51.0000001.01.00.00000051.0000001.000000...50.9567080.9348950.9855040.01836450.6771240.4754650.8232990.126854
    17vectorsimple40.7500000.01.00.50000041.0000001.000000...40.9686940.9240690.9977440.03150540.5845350.1753240.8178120.292301
    \n", + "

    18 rows × 27 columns

    \n", + "
    " + ], + "text/plain": [ + " mode question_complexity context_precision \\\n", + " count \n", + "0 entity search+vector multi_context 5 \n", + "1 entity search+vector reasoning 5 \n", + "2 entity search+vector simple 4 \n", + "3 fulltext multi_context 6 \n", + "4 fulltext reasoning 5 \n", + "5 fulltext simple 4 \n", + "6 global search+vector+fulltext multi_context 5 \n", + "7 global search+vector+fulltext reasoning 4 \n", + "8 global search+vector+fulltext simple 3 \n", + "9 graph+vector multi_context 6 \n", + "10 graph+vector reasoning 5 \n", + "11 graph+vector simple 4 \n", + "12 graph+vector+fulltext multi_context 6 \n", + "13 graph+vector+fulltext reasoning 5 \n", + "14 graph+vector+fulltext simple 4 \n", + "15 vector multi_context 6 \n", + "16 vector reasoning 5 \n", + "17 vector simple 4 \n", + "\n", + " context_recall ... \\\n", + " mean min max std count mean min ... \n", + "0 0.800000 0.0 1.0 0.447214 5 0.561905 0.142857 ... \n", + "1 0.800000 0.0 1.0 0.447214 5 0.250000 0.000000 ... \n", + "2 0.500000 0.0 1.0 0.577350 4 0.500000 0.000000 ... \n", + "3 0.833333 0.0 1.0 0.408248 6 0.952381 0.714286 ... \n", + "4 1.000000 1.0 1.0 0.000000 5 1.000000 1.000000 ... \n", + "5 1.000000 1.0 1.0 0.000000 4 1.000000 1.000000 ... \n", + "6 0.800000 0.0 1.0 0.447214 5 0.511905 0.142857 ... \n", + "7 0.500000 0.0 1.0 0.577350 4 0.125000 0.000000 ... \n", + "8 0.666667 0.0 1.0 0.577350 3 0.666667 0.000000 ... \n", + "9 0.833333 0.0 1.0 0.408248 6 0.952381 0.714286 ... \n", + "10 1.000000 1.0 1.0 0.000000 5 1.000000 1.000000 ... \n", + "11 1.000000 1.0 1.0 0.000000 4 1.000000 1.000000 ... \n", + "12 0.833333 0.0 1.0 0.408248 6 0.952381 0.714286 ... \n", + "13 1.000000 1.0 1.0 0.000000 5 1.000000 1.000000 ... \n", + "14 1.000000 1.0 1.0 0.000000 4 1.000000 1.000000 ... \n", + "15 0.833333 0.0 1.0 0.408248 6 0.910714 0.714286 ... \n", + "16 1.000000 1.0 1.0 0.000000 5 1.000000 1.000000 ... \n", + "17 0.750000 0.0 1.0 0.500000 4 1.000000 1.000000 ... \n", + "\n", + " answer_relevancy \\\n", + " count mean min max std \n", + "0 5 0.944288 0.897861 0.970096 0.028123 \n", + "1 5 0.967252 0.953466 0.985486 0.011735 \n", + "2 4 0.976775 0.950704 1.000000 0.020596 \n", + "3 6 0.939813 0.930814 0.955302 0.009615 \n", + "4 5 0.954965 0.934895 0.974246 0.014387 \n", + "5 4 0.969242 0.924026 1.000000 0.032231 \n", + "6 5 0.934088 0.900393 0.967728 0.029599 \n", + "7 4 0.953706 0.933291 0.966764 0.014332 \n", + "8 3 0.975329 0.973230 0.978811 0.003037 \n", + "9 6 0.930291 0.897861 0.957943 0.026410 \n", + "10 5 0.764748 0.000000 0.974305 0.427745 \n", + "11 4 0.944675 0.914451 0.989475 0.033573 \n", + "12 6 0.942806 0.922784 0.955302 0.013306 \n", + "13 5 0.935275 0.892618 0.962012 0.026796 \n", + "14 4 0.972342 0.926690 0.999998 0.032359 \n", + "15 6 0.935297 0.914959 0.955338 0.013688 \n", + "16 5 0.956708 0.934895 0.985504 0.018364 \n", + "17 4 0.968694 0.924069 0.997744 0.031505 \n", + "\n", + " answer_correctness \n", + " count mean min max std \n", + "0 5 0.742496 0.523471 0.992269 0.170004 \n", + "1 5 0.803536 0.565711 0.943629 0.147004 \n", + "2 4 0.537766 0.172675 0.733410 0.251963 \n", + "3 6 0.803399 0.437395 0.995587 0.208676 \n", + "4 5 0.853349 0.619032 0.996704 0.187401 \n", + "5 4 0.672318 0.175373 0.940164 0.339199 \n", + "6 5 0.735539 0.609525 0.909184 0.123181 \n", + "7 4 0.727843 0.488364 0.846143 0.162029 \n", + "8 3 0.394594 0.172125 0.665870 0.250464 \n", + "9 6 0.742180 0.491398 0.918170 0.188076 \n", + "10 5 0.858412 0.670062 0.996556 0.137474 \n", + "11 4 0.559433 0.174966 0.845223 0.300916 \n", + "12 6 0.736784 0.437216 0.990246 0.237939 \n", + "13 5 0.786999 0.455712 0.946683 0.190876 \n", + "14 4 0.643641 0.175082 0.934310 0.339174 \n", + "15 6 0.813315 0.544215 0.991202 0.156961 \n", + "16 5 0.677124 0.475465 0.823299 0.126854 \n", + "17 4 0.584535 0.175324 0.817812 0.292301 \n", + "\n", + "[18 rows x 27 columns]" + ] + }, + "execution_count": 85, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "visual_df = eval_df.groupby(['mode','question_complexity'])[['context_precision','context_recall','faithfulness', 'answer_relevancy','answer_correctness']].agg(['count','mean','min','max','std']).reset_index()\n", + "visual_df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Analysing each metric " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 1. Faithfulness\n", + "\n", + "This measures the factual consistency of the generated answer against the given context" + ] + }, + { + "cell_type": "code", + "execution_count": 92, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
    \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
    modequestion_complexitymeanminmaxstd
    0entity search+vectormulti_context0.3475000.0000000.8000000.296911
    1entity search+vectorreasoning0.5303270.0000000.9000000.330579
    2entity search+vectorsimple0.3833330.0000001.0000000.433333
    3fulltextmulti_context0.7382640.5454550.9285710.171521
    4fulltextreasoning0.9064940.7142861.0000000.133204
    5fulltextsimple0.7514880.6250000.8888890.110986
    6global search+vector+fulltextmulti_context0.4938390.1428570.8000000.235594
    7global search+vector+fulltextreasoning0.5370850.3000000.6875000.168360
    8global search+vector+fulltextsimple0.1944440.0000000.3333330.173472
    9graph+vectormulti_context0.8103110.3750001.0000000.233402
    10graph+vectorreasoning0.9066670.5333331.0000000.208700
    11graph+vectorsimple0.7460320.4285711.0000000.297804
    12graph+vector+fulltextmulti_context0.8440240.6363641.0000000.147066
    13graph+vector+fulltextreasoning0.9200000.6000001.0000000.178885
    14graph+vector+fulltextsimple0.8928570.5714291.0000000.214286
    15vectormulti_context0.7261150.5000001.0000000.203947
    16vectorreasoning0.9066670.7000001.0000000.136219
    17vectorsimple0.7083330.3333331.0000000.276385
    \n", + "
    " + ], + "text/plain": [ + " mode question_complexity mean min \\\n", + "0 entity search+vector multi_context 0.347500 0.000000 \n", + "1 entity search+vector reasoning 0.530327 0.000000 \n", + "2 entity search+vector simple 0.383333 0.000000 \n", + "3 fulltext multi_context 0.738264 0.545455 \n", + "4 fulltext reasoning 0.906494 0.714286 \n", + "5 fulltext simple 0.751488 0.625000 \n", + "6 global search+vector+fulltext multi_context 0.493839 0.142857 \n", + "7 global search+vector+fulltext reasoning 0.537085 0.300000 \n", + "8 global search+vector+fulltext simple 0.194444 0.000000 \n", + "9 graph+vector multi_context 0.810311 0.375000 \n", + "10 graph+vector reasoning 0.906667 0.533333 \n", + "11 graph+vector simple 0.746032 0.428571 \n", + "12 graph+vector+fulltext multi_context 0.844024 0.636364 \n", + "13 graph+vector+fulltext reasoning 0.920000 0.600000 \n", + "14 graph+vector+fulltext simple 0.892857 0.571429 \n", + "15 vector multi_context 0.726115 0.500000 \n", + "16 vector reasoning 0.906667 0.700000 \n", + "17 vector simple 0.708333 0.333333 \n", + "\n", + " max std \n", + "0 0.800000 0.296911 \n", + "1 0.900000 0.330579 \n", + "2 1.000000 0.433333 \n", + "3 0.928571 0.171521 \n", + "4 1.000000 0.133204 \n", + "5 0.888889 0.110986 \n", + "6 0.800000 0.235594 \n", + "7 0.687500 0.168360 \n", + "8 0.333333 0.173472 \n", + "9 1.000000 0.233402 \n", + "10 1.000000 0.208700 \n", + "11 1.000000 0.297804 \n", + "12 1.000000 0.147066 \n", + "13 1.000000 0.178885 \n", + "14 1.000000 0.214286 \n", + "15 1.000000 0.203947 \n", + "16 1.000000 0.136219 \n", + "17 1.000000 0.276385 " + ] + }, + "execution_count": 92, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "faithfulness_df = eval_df.groupby(['mode', 'question_complexity']).agg({\n", + " 'faithfulness': ['mean', 'min', 'max', 'std']\n", + "}).reset_index()\n", + "faithfulness_df.columns = ['mode', 'question_complexity', 'mean', 'min', 'max', 'std']\n", + "faithfulness_df" + ] + }, + { + "cell_type": "code", + "execution_count": 93, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABJ4AAAJOCAYAAAD2/c3/AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pXeV/AAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzddVhU6dsH8O+AAiKlgoLIghgoiqK4tgsqCjZ2o5jrit1rd3e3rrl2N3atrWt3BzYKKnW/f/jO+TEMKCgDA/v9XNdcyplnZu5nTsw593lCJSICIiIiIiIiIiKiJGaQ0gEQEREREREREVHaxMQTERERERERERHpBBNPRERERERERESkE0w8ERERERERERGRTjDxREREREREREREOsHEExERERERERER6QQTT0REREREREREpBNMPBERERERERERkU4w8URERERERERERDrBxBMREf0ULy8veHl5pXQYOuHk5ITq1aundBg/7fTp0yhdujQyZswIlUqFCxcu6PTz7t+/D5VKhSVLliS47IQJExL03rt27YK7uztMTEygUqnw7t07ncRFiaNSqTBkyJBk+awlS5ZApVLhzJkzyfJ5ye3gwYNQqVQ4ePBgSoeSaC1btoSTk1NKh5Es0vJvn645OTmhZcuWOnt/9THi/v37OvsMIkocJp6IiH7CvXv3EBgYiLx588LU1BSmpqZwdXVFx44dcenSpZQOT684OTlBpVIpDxMTE+TJkwe9evXCmzdvkjWWFy9eoGfPnsiXLx9MTU2RMWNGeHh4YMSIEYlKZCSlq1evYsiQIUl+ohwREYH69evjzZs3mDx5MpYtWwZHR8c4y6oveON6NGrU6Kfi2LFjx08nJl6/fo0GDRogQ4YMmDlzJpYtW4aMGTP+1HumNur10aZNmzif79+/v1Lm1atXiX7/48ePY8iQISm2H+iTli1bQqVSwcLCAp8+fdJ6/tatW8p3ndDEKf2PiGDZsmX47bffYGVlBVNTU7i5uWHEiBEICwtL6fAA6O64nBT08XdMn82aNYs3HYhSULqUDoCIKLXatm0bGjZsiHTp0qFp06YoXLgwDAwMcP36dWzYsAGzZ8/GvXv34r3I/y9yd3dHjx49AACfP3/G2bNnMWXKFBw6dAinTp1KlhhOnz6NqlWr4uPHj2jWrBk8PDwAAGfOnMGYMWNw+PBh7NmzJ1li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jUtE9AN69+4NU1NTtGrVCi9evNB6PjF3hqtWrYqoqCjMmDFDY/nkyZOhUqlQpUoVAF8vOqytrTXGOgC+TpMcn9hjTE2fPh0AlPesU6cODA0NMXToUK2YRQSvX78GABQrVgw2NjaYM2eOMhU68HXK4rgu+BNj69atAKAkr9QXIbHjUc9E9DN+//132NnZoUePHrh586bW88HBwRgxYkSi39fQ0FAr3rVr1+LJkycJfg91oigh36ednR3c3d2xdOlSjfKXL1/Gnj17tC68k8rP1DMx9UusXLly4eTJkxrb5rZt2/Do0aMk+4wGDRogKipK6YoRU2RkpFKvt2/fan1H6lYq6jv06v1KzcDAQOlepi6TUD179sTgwYMxcODAeMt4eHggV65cmDBhQpxdhF++fKn8PynWk4GBAfz8/LB161acOXNG63n19xP7ezAzM0Pu3LkT/B3MmzdPo9vY7NmzERkZqRzf1Bo3bgyVSoUuXbrg7t27PzxuS/ny5TF8+HDMmDEDtra28ZarWrUqTp06hRMnTijLQkNDMW/ePDg5OSktfqpWrYqnT58q09UDX2f3mjdvnsb7JWb9xSWuY+o///yjEV9ixDz+xOz6vHfvXmX8qm8xNTVF7969cePGDWWGsZi2b9+OJUuWoEaNGnBzc1OW58qVS+v3b968eVotnho0aIATJ05g9+7dWu/97t075WZHQvbDxOwPVatWxfPnz/H3338ryyIjIzF9+nSYmZnB09Pzu++REIn5HfP29oaRkRGmTZumsf4XLlyI9+/fo1q1akkSU0zfO++IS0LXGfB1fKro6GgsXLgQ8+bNQ7p06dC6devvnndlzJgx3vWYLl06NG7cGGvWrMGSJUvg5uaW4C6/RJQwbPFERPQD8uTJg5UrV6Jx48ZwcXFB06ZNUbhwYYgI7t27h5UrV8LAwCBBU0vXqFED5cuXR//+/XH//n0ULlwYe/bswebNm9G1a1eNKePbtGmDMWPGoE2bNihWrBgOHz4c54mn2r1791CzZk34+vrixIkTWL58OZo0aaIkeXLlyoURI0agX79+uH//Pvz8/GBubo579+5h48aNaNeuHXr27In06dNjxIgRaN++PSpUqICGDRvi3r17WLx4caJalDx58gTLly8H8PWO68WLFzF37lxYW1sr3ewsLCzw22+/Ydy4cYiIiIC9vT327NmD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A3n8+LHWc0T0c1QiSTRSIBER6Y0hQ4Zg6NChePnyZYLHGCIiSqs2b94MPz8/HD58WJm2nvRLREQEatSogaCgIGzduvWHZ5ejlJEWzjuKFCmCzJkzIygoKKVDIUpzOMYTEREREaVp8+fPh7OzM8qWLZvSoVA80qdPj/Xr18Pd3R3169fHuXPnUjok+g85c+YMLly4AH9//5QOhShN4hhPRERERJQmrV69GpcuXcL27dsxdepUnc6uSD8vY8aMOH36dEqHQf8hly9fxtmzZzFx4kTY2dmhYcOGKR0SUZrExBMRERERpUmNGzeGmZkZWrdu/c2Bh4nov2ndunUYNmwYXFxcsGrVKpiYmKR0SERpEsd4IiIiIiIiIiIineAYT0REREREREREpBNMPBERERERERERkU5wjCfSEB0djadPn8Lc3JwDcBIRERERERFRnEQEHz58QPbs2WFgEH+7JiaeSMPTp0/h4OCQ0mEQERERERERUSrw6NEj5MiRI97nmXgiDebm5gC+bjgWFhYpHA0RERERERER6aOQkBA4ODgoeYT4MPFEGtTd6ywsLJh4IiIiIiIiIqJv+t4wPRxcnIiIiIiIiIiIdIKJJyIiIiIiIiIi0gkmnoiIiIiIiIiISCc4xhMRERERERERpVpRUVGIiIhI6TDSnPTp08PQ0PCn34eJJyIiIiIiIiJKdUQEz58/x7t371I6lDTLysoKtra23x1A/FuYeCIiIiIiIiKiVEeddMqaNStMTU1/KjlCmkQEYWFhCA4OBgDY2dn98Hsx8UREREREREREqUpUVJSSdMqSJUtKh5MmZciQAQAQHByMrFmz/nC3Ow4uTkRERERERESpinpMJ1NT0xSOJG1Tf78/M4YWE09ERERERERElCqxe51uJcX3y8QTERERERERERHpBBNPREREREREREQpTKVSYdOmTSkdRpLj4OJERERERESpnFPf7Qkue39MNR1GQpS6tWzZEkuXLkX79u0xZ84cjec6duyIWbNmoUWLFliyZMl33+vgwYMoX7483r59Cysrq++Wf/bsGTJlyvSDkesvtngiIiIiIiIiIvp/Dg4OWL16NT59+qQs+/z5M1auXIlffvklyT8vPDwcAGBrawtjY+Mkf/+UxsQTEREREREREdH/K1q0KBwcHLBhwwZl2YYNG/DLL7+gSJEiyrLo6GiMHj0a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4aQ56dOn/6mWTmpMPBERERERERFRqmVoaJgkCZLv4UyEP4aDixMRERERERERkU4w8URERERERERERDrBxBMREREREREREekEE09ERERERERERKQTTDwREREREREREZFOMPFEREREREREREQ6wcQTERERERERERHpBBNPRERERERERESkE0w8ERERERERERGRTjDxREREREREREREOsHEExERERERERER6QQTT0REREREREREpBNMPBERERERERERkU4w8URERERERERERDrBxBMREREREREREekEE09ERERERERERKQTTDwREREREREREZFOMPFEREREREREREQ6wcQTERERERERERHpBBNPRERERERERESkE0w8ERERERERERGRTjDxREREREREREREOsHEExERERERERER6QQTT0REREREREREpBNMPBERERERERERkU4w8URERERERERERDrBxJOemzlzJpycnGBiYoISJUrg1KlT3yz/7t07dOzYEXZ2djA2NkbevHmxY8eOZIqWiIiIiIiIiOh/0qV0ABS/v//+G927d8ecOXNQokQJTJkyBT4+Prhx4wayZs2qVT48PByVKlVC1qxZsW7dOtjb2+PBgwewsrJK/uCJiIiIiIiI6D+PiSc9NmnSJLRt2xYBAQEAgDlz5mD79u1YtGgR+vbtq1V+0aJFePPmDY4fP4706dMDAJycnJIzZCIiIiIiIiIiBbva6anw8HCcPXsW3t7eyjIDAwN4e3vjxIkTcb5my5YtKFWqFDp27Ihs2bKhYMGCGDVqFKKiouL9nC9fviAkJETjQURERERERESUFJh40lOvXr1CVFQUsmXLprE8W7ZseP78eZyvuXv3LtatW4eoqCjs2LEDAwcOxMSJEzFixIh4P2f06NGwtLRUHg4ODklaDyIiIiIiIiL672LiKQ2Jjo5G1qxZMW/ePHh4eKBhw4bo378/5syZE+9r+vXrh/fv3yuPR48eJWPERERERERERJSWcYwnPWVtbQ1DQ0O8ePFCY/mLFy9ga2sb52vs7OyQPn16GBoaKsvy58+P58+fIzw8HEZGRlqvMTY2hrGxcdIGT0REREREREQEtnjSW0ZGRvDw8EBQUJCyLDo6GkFBQShVqlScrylTpgxu376N6OhoZdnNmzdhZ2cXZ9KJiIiIiIiIiEiXmHjSY927d8f8+fOxdOlSXLt2DR06dEBoaKgyy52/vz/69eunlO/QoQPevHmDLl264ObNm9i+fTtGjRqFjh07plQViIiIiIiIiOg/jF3t9FjDhg3x8uVLDBo0CM+fP4e7uzt27dqlDDj+8OFDGBj8L3fo4OCA3bt3o1u3bihUqBDs7e3RpUsX9OnTJ6WqQERERERERET/YUw86bnAwEAEBgbG+dzBgwe1lpUqVQonT57UcVRERERERERERN/HrnZERERERERERKQTTDwREREREREREZFOMPFEREREREREREQ6wcQTERERERERERHpBBNPRERERERERESkE0w8ERERERERERGRTjDxREREREREREREOsHEUxJ69OgRHj9+rPx96tQpdO3aFfPmzUvBqIiIiIiIiIiIUgYTT0moSZMmOHDgAADg+fPnqFSpEk6dOoX+/ftj2LBhKRwdEREREREREVHyYuIpCV2+fBnFixcHAKxZswYFCxbE8ePHsWLFCixZsiRlgyMiIiIiIiIiSmZMPCWhiIgIGBsbAwD27duHmjVrAgDy5cuHZ8+epWRoRERERERERETJjomnJFSgQAHMmTMHR44cwd69e+Hr6wsAePr0KbJkyZLC0RERERERERERJa90KR1AWjJ27FjUrl0b48ePR4sWLVC4cGEAwJYtW5QueERERPTznPpuT3DZ+2Oq6TASIiIiIvoWJp6SkJeXF169eoWQkBBkypRJWd6uXTuYmpqmYGRERERERERERMmPiackJiI4e/Ys7ty5gyZNmsDc3BxGRkZMPNFP4Z19IiIiIiIiSo2YeEpCDx48gK+vLx4+fIgvX76gUqVKMDc3x9ixY/HlyxfMmTMnpUMkIiIiIiIiIko2HFw8CXXp0gXFihXD27dvkSFDBmV57dq1ERQUlIKRERERERERERElP7Z4SkJHjhzB8ePHYWRkpLHcyckJT548SaGoiIiIiIiIiIhSBls8JaHo6GhERUVpLX/8+DHMzc1TICIiIiIiIiIiopTDxFMSqly5MqZMmaL8rVKp8PHjRwwePBhVq1ZNucCIiIiIiIiIiFIAu9oloYkTJ8LHxweurq74/PkzmjRpglu3bsHa2hqrVq1K6fCIiIiIiIiIiJIVE09JKEeOHLh48SJWr16NS5cu4ePHj2jdujWaNm2qMdg4EREREREREdF/ARNPSSxdunRo1qxZSodBRERERERERJTimHhKQn/99dc3n/f390+mSIiIiIiIiIiIUh4TT0moS5cuGn9HREQgLCwMRkZGMDU1ZeKJiIiSnVPf7Qkue39MNR1GQkRERET/RZzVLgm9fftW4/Hx40fcuHEDZcuW5eDiRERERERERPSfw8STjuXJkwdjxozRag1FRERERERERJTWMfGUDNKlS4enT5+mdBhERERERERERMmKYzwloS1btmj8LSJ49uwZZsyYgTJlyqRQVEREREREREREKYOJpyTk5+en8bdKpYKNjQ0qVKiAiRMnpkxQREREREREREQphImnJBQdHZ3SIRARERERERER6Q2O8URERERERERERDrBFk8/qXv37gkuO2nSJB1GQkRERERERESkX5h4+knnz59PUDmVSqXjSIiIiIiIiIiI9AsTTz/pwIEDKR0CEREREREREZFe4hhPRERERERERESkE2zxlMTOnDmDNWvW4OHDhwgPD9d4bsOGDSkUFRERERERERFR8mOLpyS0evVqlC5dGteuXcPGjRsRERGBK1euYP/+/bC0tEzp8IiIiIiIiIiIkhUTT0lo1KhRmDx5MrZu3QojIyNMnToV169fR4MGDfDLL7+kdHhERERERERERMmKiackdOfOHVSrVg0AYGRkhNDQUKhUKnTr1g3z5s1L4eiIiIiIiIiIiJIXE09JKFOmTPjw4QMAwN7eHpcvXwYAvHv3DmFhYSkZGhERERERERFRsmPiKQmoE0y//fYb9u7dCwCoX78+unTpgrZt26Jx48aoWLFiSoZIRERERERERJTsOKtdEihUqBB+/fVX+Pn5oX79+gCA/v37I3369Dh+/Djq1q2LAQMGpHCURKnckEQM0D/kve7iICIiIiIiogRj4ikJHDp0CIsXL8bo0aMxcuRI1K1bF23atEHfvn1TOjQiIiIiIiIiohTDrnZJoFy5cli0aBGePXuG6dOn4/79+/D09ETevHkxduxYPH/+PKVDJCIiIiIiIiJKdkw8JaGMGTMiICAAhw4dws2bN1G/fn3MnDkTv/zyC2rWrJnS4RERERERERERJSsmnnQkd+7c+PPPPzFgwACYm5tj+/btKR0SEREREREREVGyYuJJBw4fPoyWLVvC1tYWvXr1Qp06dXDs2LEfeq+ZM2fCyckJJiYmKFGiBE6dOpWg161evRoqlQp+fn4/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devo1avXPdscP3483+SliIiIPVLiSUREROyWxWLh5MmTnDhxAovFcs/6IkWKMGDAAEJDQ1m3bh0nTpygT58+3L59m+DgYAD69+/P6dOnCQ0N5euvv+aTTz4hOjo6z3HCwsLYtWsXgwYN4vDhw5w+fZpVq1bZelutWbOGDz74gMOHD3P+/HkWLVpETk4Ovr6++cbt4eFB7dq12bFjh22ZyWRi7ty5nDhxgoCAAPbt28eFCxf4/PPPad26Nc2aNaNfv37AnaFUL7zwApMnT+bkyZPEx8fz1ltv5TnHP//5T77//ntee+019u/fzzfffENcXBw9e/YkOzubvXv3MnHiRBISErhw4QKxsbF8++23tuSKj48PR48e5euvv+batWv39KgCGDhwIBcvXmTw4MEkJSWxatUqxowZk2+B9N9iwoQJlC9fnnr16rFo0SJOnDjB6dOnmT9/Pn5+fty6dYtKlSrRpk0b+vTpw44dOzhy5AjdunWjbNmytGnT5nefO9fOnTuJjIzk1KlTzJw5k88//5whQ4bku23Xrl156qmnaNOmDdu3b+fs2bNs3bqVkJAQLl26BNz5PStfvjxvvfUWU6dOJTs7mzfffPO+5/fx8WHv3r2cO3eOa9eu2ZKRFouFoKAgRo0aRaVKle4ZEgiwfft2mjZt+ofvgYiIyMOgxJOIiIjYNTc3N9zc3O67fvLkyQQEBNC9e3dq167NmTNniIuLs9Uy8vb2Zvny5axcuZKaNWsSFRXFxIkT8xzjueeeIz4+nlOnTvHSSy/h5+dHRESEbdY1d3d3YmNj+dvf/kbVqlWJiopi6dKlVKtW7b5x9e7d+56hWQ0aNGDPnj1YLBZatGjB008/TadOnWjTpg2rV6/Ok1ybP38+WVlZPP/88wwdOvSemeTKlCnDzp07yc7OpmnTptSoUYOhQ4fi7u6O2WzGzc2Nbdu28eqrr1K5cmXeeust3nvvPVq0aAFAnz598PX1pU6dOnh4eOTpNZarbNmyrF27ln379lGzZk369+9PcHDwPUmw36pEiRLs2bOHbt26MX78ePz8/HjppZdYunQp77zzjq0X0YIFC3j++edp1aoV/v7+GIbB2rVr7xlK93sMHz6chIQE/Pz8GD9+PFOnTs23Vx3cqSO1bds2vL29ad++PVWrViU4OJgff/wRNzc3Fi1aZJtBz8HBgSJFirB48WLmzJnDV199le8x33zzTSwWC88++yweHh5cuHDBti44OBir1ZrvLI67d+/mxo0bdOjQ4Q/fAxERkYfBZPzaCo8iIiIi8qulp6fj6+vLp59+mm+vFYCcnByCg4OJi4sjPj7eVgdKHiwfHx+GDh3K0KFDCzqUfG3fvp3GjRtz8eJFvLy88qzr3LkzNWvWJDw8vICiExER+W3U40lERETkAXBxcWHRokVcu3btvtuYzWbmzZtHWFgY27dvf4jRiT3KyMjg0qVLjB07lo4dO96TdLJardSoUYM33nijgCIUERH57dTjSURERESeKPba4yk6Oprg4GBq1arFF198QdmyZQs6JBERkT9MiScREREREREREXkgNNROREREREREREQeCCWeRERERERERETkgVDiSUREREREREREHgglnkRERERERERE5IFQ4klERERERERERB4IJZ5EREREREREROSBUOJJREREREREREQeCCWeRERERERERETkgVDiSUREREREREREHoj/B2AMRvW36A4iAAAAAElFTkSuQmCC", + "text/plain": [ + "
    " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Grouped bar chart\n", + "metrics = ['mean', 'std']\n", + "x = np.arange(len(faithfulness_df['mode'])) # Label locations\n", + "width = 0.2 # Bar width\n", + "fig, ax = plt.subplots(figsize=(12, 6))\n", + "for i, metric in enumerate(metrics):\n", + " ax.bar(x + i * width, faithfulness_df[metric], width, label=metric)\n", + "ax.set_xticks(x + width * 1.5)\n", + "ax.set_xticklabels(faithfulness_df['mode'] + ' (' + faithfulness_df['question_complexity'] + ')', rotation=45, ha='right')\n", + "ax.set_xlabel('Modes (Question Complexity)')\n", + "ax.set_ylabel('Values')\n", + "ax.set_title('Grouped Bar Chart of Faithfulness Metrics by Mode and Question Complexity')\n", + "ax.legend(title=\"Metrics\")\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. Surprisingly faithfulness score is less in \"entity search + vector\" and \"global search + vector + fulltext \" modes\n", + "2. We can observe that faithfulness score increases on reasoning question for most of the modes\n", + "3. All modes struggle on simple questions." + ] + }, + { + "cell_type": "code", + "execution_count": 112, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
    \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
    questionmodeanswerfaithfulness
    10How does the integrated focused cost leadership strategy help competitors compete with Amazon in the book industry?global search+vector+fulltextThe integrated focused cost leadership strategy helps competitors like Barnes and Noble compete with Amazon in the book industry by allowing them to offer a unique value proposition. By combining cost leadership with differentiation, Barnes and Noble can focus on specific market segments or niches where they can provide distinct products or services at competitive prices. This strategy enables them to target specific customer needs effectively while maintaining cost efficiency, thereby creating a competitive advantage against Amazon's broader market approach.0.250000
    16What is the competitive strategy of Barnes and Noble in the e-commerce industry?global search+vector+fulltextBarnes and Noble in the e-commerce industry employs an integrated focused cost leadership/differentiation strategy. This strategy combines elements of cost leadership and differentiation to set itself apart from competitors like Amazon and eBay. By focusing on cost efficiency while also offering unique and differentiated products or services, Barnes and Noble aims to carve out a competitive position in the market.0.333333
    22Why should online retailers like Amazon be careful about disclosing online sales taxes in their advertisements?global search+vector+fulltextOnline retailers like Amazon should be cautious about disclosing online sales taxes in their advertisements to maintain transparency and compliance with regulations. By clearly stating the inclusion of sales taxes, they build trust with customers and avoid potential legal issues related to false advertising or misleading practices. Additionally, disclosing online sales taxes helps prevent any misunderstandings or surprises for customers during the checkout process, leading to a smoother shopping experience and reducing the risk of customer dissatisfaction or complaints.0.000000
    28How threatening are substitute products to Amazon's patented tech and customer service?global search+vector+fulltextSubstitute products can pose a moderate threat to Amazon's patented technology and customer service. While Amazon's patents provide a level of protection for its innovations, substitute products could still impact its market share and competitive position. Amazon's strong customer service reputation may mitigate some of this threat by fostering customer loyalty. However, continuous innovation and strategic differentiation are crucial for Amazon to stay ahead of potential substitutes in the rapidly evolving e-commerce landscape.0.300000
    57What strategies are Amazon's book competitors using for market share and how does it compare to Amazon's?global search+vector+fulltextAmazon's book competitors employ various strategies to compete for market share. eBay utilizes both cost leadership and differentiation strategies, aiming to offer competitive pricing and a unique value proposition to customers. Barnes and Noble integrates a focused cost leadership/differentiation strategy, focusing on specific market segments while offering differentiated products and services. Wal-Mart, as the world's largest retail chain, primarily focuses on a cost leadership approach, leveraging its scale to provide competitive prices.\\n\\nIn comparison, Amazon employs a mix of strategies, heavily investing in technologies like video content, cloud services, and its Kindle product. It leverages technologies such as Elastic Block Storage (EBS) and 1-Click Ordering to enhance operations and customer experience. Amazon's strategic focus on innovation, technology, and global market expansion sets it apart from its competitors, allowing it to maintain a strong position in the e-commerce landscape.0.454545
    69What strategies do Amazon's book competitors use to attract price-sensitive customers and grow market share, leveraging online shopping and unique, cheap books?global search+vector+fulltextAmazon's book competitors employ various strategies to attract price-sensitive customers and expand their market share in the realm of online shopping. eBay, Barnes and Noble, and Wal-Mart utilize different approaches to cater to this segment:\\n\\n1. **eBay**: Utilizes both cost leadership and differentiation strategies to appeal to price-sensitive customers. It offers a wide range of products, including books, at competitive prices while also providing a unique platform for auctions and second-hand items.\\n\\n2. **Barnes and Noble**: Integrates a focused cost leadership/differentiation strategy to stand out in the market. By offering a mix of affordable books along with unique and high-quality selections, they target price-sensitive customers seeking value and variety.\\n\\n3. **Wal-Mart**: Focuses on a cost leadership approach, leveraging its vast retail chain to provide competitive pricing on books and other products. By emphasizing affordability and a wide selection, Wal-Mart aims to attract price-sensitive customers looking for budget-friendly options.\\n\\nThese competitors aim to leverage online shopping platforms to reach a broader audience of price-sensitive customers while offering unique and affordable book selections to enhance their market share in the competitive e-commerce landscape.0.142857
    \n", + "
    " + ], + "text/plain": [ + " question \\\n", + "10 How does the integrated focused cost leadership strategy help competitors compete with Amazon in the book industry? \n", + "16 What is the competitive strategy of Barnes and Noble in the e-commerce industry? \n", + "22 Why should online retailers like Amazon be careful about disclosing online sales taxes in their advertisements? \n", + "28 How threatening are substitute products to Amazon's patented tech and customer service? \n", + "57 What strategies are Amazon's book competitors using for market share and how does it compare to Amazon's? \n", + "69 What strategies do Amazon's book competitors use to attract price-sensitive customers and grow market share, leveraging online shopping and unique, cheap books? \n", + "\n", + " mode \\\n", + "10 global search+vector+fulltext \n", + "16 global search+vector+fulltext \n", + "22 global search+vector+fulltext \n", + "28 global search+vector+fulltext \n", + "57 global search+vector+fulltext \n", + "69 global search+vector+fulltext \n", + "\n", + " answer \\\n", + "10 The integrated focused cost leadership strategy helps competitors like Barnes and Noble compete with Amazon in the book industry by allowing them to offer a unique value proposition. By combining cost leadership with differentiation, Barnes and Noble can focus on specific market segments or niches where they can provide distinct products or services at competitive prices. This strategy enables them to target specific customer needs effectively while maintaining cost efficiency, thereby creating a competitive advantage against Amazon's broader market approach. \n", + "16 Barnes and Noble in the e-commerce industry employs an integrated focused cost leadership/differentiation strategy. This strategy combines elements of cost leadership and differentiation to set itself apart from competitors like Amazon and eBay. By focusing on cost efficiency while also offering unique and differentiated products or services, Barnes and Noble aims to carve out a competitive position in the market. \n", + "22 Online retailers like Amazon should be cautious about disclosing online sales taxes in their advertisements to maintain transparency and compliance with regulations. By clearly stating the inclusion of sales taxes, they build trust with customers and avoid potential legal issues related to false advertising or misleading practices. Additionally, disclosing online sales taxes helps prevent any misunderstandings or surprises for customers during the checkout process, leading to a smoother shopping experience and reducing the risk of customer dissatisfaction or complaints. \n", + "28 Substitute products can pose a moderate threat to Amazon's patented technology and customer service. While Amazon's patents provide a level of protection for its innovations, substitute products could still impact its market share and competitive position. Amazon's strong customer service reputation may mitigate some of this threat by fostering customer loyalty. However, continuous innovation and strategic differentiation are crucial for Amazon to stay ahead of potential substitutes in the rapidly evolving e-commerce landscape. \n", + "57 Amazon's book competitors employ various strategies to compete for market share. eBay utilizes both cost leadership and differentiation strategies, aiming to offer competitive pricing and a unique value proposition to customers. Barnes and Noble integrates a focused cost leadership/differentiation strategy, focusing on specific market segments while offering differentiated products and services. Wal-Mart, as the world's largest retail chain, primarily focuses on a cost leadership approach, leveraging its scale to provide competitive prices.\\n\\nIn comparison, Amazon employs a mix of strategies, heavily investing in technologies like video content, cloud services, and its Kindle product. It leverages technologies such as Elastic Block Storage (EBS) and 1-Click Ordering to enhance operations and customer experience. Amazon's strategic focus on innovation, technology, and global market expansion sets it apart from its competitors, allowing it to maintain a strong position in the e-commerce landscape. \n", + "69 Amazon's book competitors employ various strategies to attract price-sensitive customers and expand their market share in the realm of online shopping. eBay, Barnes and Noble, and Wal-Mart utilize different approaches to cater to this segment:\\n\\n1. **eBay**: Utilizes both cost leadership and differentiation strategies to appeal to price-sensitive customers. It offers a wide range of products, including books, at competitive prices while also providing a unique platform for auctions and second-hand items.\\n\\n2. **Barnes and Noble**: Integrates a focused cost leadership/differentiation strategy to stand out in the market. By offering a mix of affordable books along with unique and high-quality selections, they target price-sensitive customers seeking value and variety.\\n\\n3. **Wal-Mart**: Focuses on a cost leadership approach, leveraging its vast retail chain to provide competitive pricing on books and other products. By emphasizing affordability and a wide selection, Wal-Mart aims to attract price-sensitive customers looking for budget-friendly options.\\n\\nThese competitors aim to leverage online shopping platforms to reach a broader audience of price-sensitive customers while offering unique and affordable book selections to enhance their market share in the competitive e-commerce landscape. \n", + "\n", + " faithfulness \n", + "10 0.250000 \n", + "16 0.333333 \n", + "22 0.000000 \n", + "28 0.300000 \n", + "57 0.454545 \n", + "69 0.142857 " + ] + }, + "execution_count": 112, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Lets check question answer for global search where it has scored low\n", + "pd.set_option(\"display.max_colwidth\", None)\n", + "eval_df[[\"question\",\"mode\",\"answer\",\"faithfulness\"]][(eval_df['mode']==\"global search+vector+fulltext\") & (eval_df['faithfulness'] <0.5)]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 2. Answer Relevancy\n", + "\n", + "Scores the relevancy of the answer according to the given question" + ] + }, + { + "cell_type": "code", + "execution_count": 94, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
    \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
    modequestion_complexitymeanminmaxstd
    0entity search+vectormulti_context0.9442880.8978610.9700960.028123
    1entity search+vectorreasoning0.9672520.9534660.9854860.011735
    2entity search+vectorsimple0.9767750.9507041.0000000.020596
    3fulltextmulti_context0.9398130.9308140.9553020.009615
    4fulltextreasoning0.9549650.9348950.9742460.014387
    5fulltextsimple0.9692420.9240261.0000000.032231
    6global search+vector+fulltextmulti_context0.9340880.9003930.9677280.029599
    7global search+vector+fulltextreasoning0.9537060.9332910.9667640.014332
    8global search+vector+fulltextsimple0.9753290.9732300.9788110.003037
    9graph+vectormulti_context0.9302910.8978610.9579430.026410
    10graph+vectorreasoning0.7647480.0000000.9743050.427745
    11graph+vectorsimple0.9446750.9144510.9894750.033573
    12graph+vector+fulltextmulti_context0.9428060.9227840.9553020.013306
    13graph+vector+fulltextreasoning0.9352750.8926180.9620120.026796
    14graph+vector+fulltextsimple0.9723420.9266900.9999980.032359
    15vectormulti_context0.9352970.9149590.9553380.013688
    16vectorreasoning0.9567080.9348950.9855040.018364
    17vectorsimple0.9686940.9240690.9977440.031505
    \n", + "
    " + ], + "text/plain": [ + " mode question_complexity mean min \\\n", + "0 entity search+vector multi_context 0.944288 0.897861 \n", + "1 entity search+vector reasoning 0.967252 0.953466 \n", + "2 entity search+vector simple 0.976775 0.950704 \n", + "3 fulltext multi_context 0.939813 0.930814 \n", + "4 fulltext reasoning 0.954965 0.934895 \n", + "5 fulltext simple 0.969242 0.924026 \n", + "6 global search+vector+fulltext multi_context 0.934088 0.900393 \n", + "7 global search+vector+fulltext reasoning 0.953706 0.933291 \n", + "8 global search+vector+fulltext simple 0.975329 0.973230 \n", + "9 graph+vector multi_context 0.930291 0.897861 \n", + "10 graph+vector reasoning 0.764748 0.000000 \n", + "11 graph+vector simple 0.944675 0.914451 \n", + "12 graph+vector+fulltext multi_context 0.942806 0.922784 \n", + "13 graph+vector+fulltext reasoning 0.935275 0.892618 \n", + "14 graph+vector+fulltext simple 0.972342 0.926690 \n", + "15 vector multi_context 0.935297 0.914959 \n", + "16 vector reasoning 0.956708 0.934895 \n", + "17 vector simple 0.968694 0.924069 \n", + "\n", + " max std \n", + "0 0.970096 0.028123 \n", + "1 0.985486 0.011735 \n", + "2 1.000000 0.020596 \n", + "3 0.955302 0.009615 \n", + "4 0.974246 0.014387 \n", + "5 1.000000 0.032231 \n", + "6 0.967728 0.029599 \n", + "7 0.966764 0.014332 \n", + "8 0.978811 0.003037 \n", + "9 0.957943 0.026410 \n", + "10 0.974305 0.427745 \n", + "11 0.989475 0.033573 \n", + "12 0.955302 0.013306 \n", + "13 0.962012 0.026796 \n", + "14 0.999998 0.032359 \n", + "15 0.955338 0.013688 \n", + "16 0.985504 0.018364 \n", + "17 0.997744 0.031505 " + ] + }, + "execution_count": 94, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "answer_rel_df = eval_df.groupby(['mode', 'question_complexity']).agg({\n", + " 'answer_relevancy': ['mean', 'min', 'max', 'std']\n", + "}).reset_index()\n", + "answer_rel_df.columns = ['mode', 'question_complexity', 'mean', 'min', 'max', 'std']\n", + "answer_rel_df" + ] + }, + { + "cell_type": "code", + "execution_count": 95, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABJ4AAAJOCAYAAAD2/c3/AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pXeV/AAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzdd1QUVxsG8GdBiooUpYpELIgoiBUVu2LF3iuKURMVY+/G3qOIHXvv3dgVa9TErjGW2LtgV0AB4f3+8Ox8LAuKysJCnt85e5Q7d3bfuzM75Z07d1QiIiAiIiIiIiIiIkphBmkdABERERERERERZUxMPBERERERERERkU4w8URERERERERERDrBxBMREREREREREekEE09ERERERERERKQTTDwREREREREREZFOMPFEREREREREREQ6wcQTERERERERERHpBBNPRERERERERESkE0w8ERFlQJUrV0blypXTOgydcHZ2Rt26ddM6jO92+vRpeHt7I2vWrFCpVLhw4UJah/SfNHLkSKhUqrQOg5LJ2dkZHTp0SJXPOnz4MFQqFTZu3Jgqn5fa7t69C5VKhaVLl6Z1KF/tv/S77dChA5ydndM6jHRJ18dC6m3E4cOHdfYZRBkFE09ElOHcuXMHAQEBKFCgALJkyYIsWbKgUKFC6N69Oy5dupTW4ekVZ2dnqFQq5WVqagoXFxf0798fL1++TNVYQkND0a9fPxQsWBBZsmRB1qxZUaJECYwdOxavX79O1VjUrly5gpEjR+Lu3bsp+r4xMTFo1qwZXr58iWnTpmHFihXInTv3F+fbtWsXVCoVcubMibi4uBSNKT3o0KGDxvpqYmKCAgUKYPjw4fjw4UNah5ehqLcNPj4+iU5fsGCBshzOnDnz1e+vq99WeqROohgYGODBgwda09++fYvMmTNDpVIhICAgDSJM/3bs2IFatWohR44cMDU1RYECBdJkP5eUx48fY+TIkXp5AeLt27cYNWoUPD09YWZmhsyZM8Pd3R0DBw7E48eP0zo8vbN69WoEBQWldRhEeidTWgdARJSSduzYgRYtWiBTpkxo06YNPD09YWBggGvXrmHz5s2YO3cu7ty5k6yT/P+KokWLom/fvgCADx8+4OzZswgKCsKRI0dw6tSpVInh9OnTqFOnDsLDw9G2bVuUKFECAHDmzBlMnDgRR48exb59+1Il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F127dsWuXbvSOhz6D3ny5Al27tzJxDT953CMJyIiIqIMJiwsDAcOHMDGjRvx4sWLZI0ZRN/u999/x5UrVzB//nwEBAR80xMsKfUYGhoqD9EgSg137tzB8ePHsXDhQhgZGeGnn35K65CIUhUTT0REREQZjHogZVtbW8yYMUN5ihbpRo8ePRAaGoo6depg1KhRaR0OEemZI0eOwN/fHz/88AOWLVsGe3v7tA6JKFVxjCciIiIiIiIiItIJjvFEREREREREREQ6wcQTERERERERERHpBMd4Ig1xcXF4/PgxsmXLBpVKldbhEBEREREREZEeEhG8e/cOOXPmhIFB0v2amHgiDY8fP4aTk1Nah0FERERERERE6cCDBw+QK1euJKcz8UQasmXLBuDTimNubp7G0RARERERERGRPnr79i2cnJyUPEJSmHgiDerb68zNzZl4IiIiIiIiIqLP+tIwPRxcXE8dPXoU9erVQ86cOaFSqbB169YvznP48GEUL14cJiYmyJ8/P5YuXarzOImIiIiIiIiIksLEk56KiIiAp6cnZs+enaz6d+7cga+vL6pUqYILFy6gV69e6NSpE/bu3avjSImIiIiIiIiIEsdb7fRU7dq1Ubt27WTXDw4ORp48eTB16lQAgJubG/744w9MmzYNNWvW1FWYRERERERERERJYuIpgzh58iR8fHw0ymrWrIlevXp9dr6oqChERUUpf799+1YX4RERERERERHpRGxsLGJiYtI6jAzHyMgIhoaG3/0+TDxlEE+fPoWdnZ1GmZ2dHd6+fYv3798jc+bMic43YcIEjBo1KjVCJCIiIiIiIkoxIoKnT5/i9evXaR1KhmVpaQl7e/svDiD+OUw8/ccNHjwYffr0Uf5WPw6RiIiIiIiISJ+pk062trbIkiXLdyVHSJOIIDIyEmFhYQAABweHb34vJp4yCHt7e4SGhmqUhYaGwtzcPMneTgBgYmICExMTXYdHRERERERElGJiY2OVpFOOHDnSOpwMSZ1LCAsLg62t7Tffdsen2mUQZcuWRUhIiEbZ/v37UbZs2TSKiIiIiIiIiEg31GM6ZcmSJY0jydjU3+/3jKHFxJOeCg8Px4ULF3DhwgUAwJ07d3DhwgXcv38fwKdb5Pz8/JT6P//8M27fvo0BAwbg2rVrmDNnDtavX4/evXunRfhEREREREREOsfb63QrJb5fJp701JkzZ1CsWDEUK1YMANCnTx8UK1YMw4cPBwA8efJESUIBQJ48ebBz507s378fnp6emDp1KhYuXIiaNWumSfxERERERERERBzjSU9VrlwZIpLk9KVLlyY6z/nz53UYFRERERERERHpgkqlwpYtW9CwYcO0DiVFMfFERGnKedDOZNW7O9FXx5EQEekHbheJiIjSTocOHbBs2TL89NNPCA4O1pjWvXt3zJkzB+3bt0+0M0hChw8fRpUqVfDq1StYWlp+sf6TJ09gZWX1jZHrLyaeiIiIiIiISG8lNyEPMClPKcPJyQlr167FtGnTlCe7ffjwAatXr8YPP/yQ4p8XHR0NY2Nj2Nvbp/h76wMmnojSAe5siXSPvUyIiIiICACKFy+OW7duYfPmzWjTpg0AYPPmzbB1cISjU268iojGpYevERcXhyVzgrBx9TK8CAtD7rz50KVnf1T3bQDzj69RpUoVAFB6Mal7SlWuXBnu7u7IlCkTVq5cCQ8PDxw6dEjrVruHDx+if//+2Lt3L6KiouDm5obZs2ejdOnSuHjxInr16oUzZ85ApVLBxcUF8+bNQ8mSJdPkO/scJp6IiIiIiIiIiOLp2LEjlixZoiSeFi9ejAbN2+DMyT+UOotmBWLnlg0YNj4QufPkw9m/TmBIz59gld0a7RvXwqZNm9CkSRNcv34d5ubmSu8pAFi2bBm6du2K48ePJ/r54eHhqFSpEhwdHbF9+3bY29vj3LlziIuLAwC0adMGxYoVw9y5c2FoaIgLFy7AyMhIh9/It2PiiYiIiIiIiIgonrZt22Lw4MG4d+8eAOD48eP4NXCekniKjorCwlnTMH/NFniW8AIA5MrtjPOn/8TGVUvQsZkvsmfPDgCwtbXVGuPJxcUFkydPTvLzV69ejWfPnuH06dPK++TPn1+Zfv/+ffTv3x8FCxZU3k9fMfFERERERERERCkiowwTYmNjA19fXyxduhQiAl9fX1hlz6FMv3/3Nj68j8RPrRtrzBcTE42ChYt88f1LlCjx2ekXLlxAsWLFlKRTQn369EGnTp2wYsUK+Pj4oFmzZsiXL18yWpb6mHgiIqJkyygHEpT+cV0kIiIiXevYsSMCAgIAALNnz9aYFhkZAQCYtXQdbO0dNKYZmxh/8b2zZs362enxb8tLzMiRI9G6dWvs3LkTu3fvxogRI7B27Vo0atToi5+d2gzSOgAiIiIiIiIiIn1Tq1YtREdHIyYmBjVr1tSYls/FFcYmJnjy+AF+yJNX42WfMxcAwNj4UwIqNjb2qz+7SJEiuHDhAl6+fJlknQIFCqB3797Yt28fGjdujCVLlnz156QGJp6IiIiIiIiIiBIwNDTE1atXceXKFRgaGmpMy2qWDe27BGDKqKHYvmENHty9g6t/X8TqJfOxfcMaAEDu3LmhUqmwY8cOPHv2DOHh4cn+7FatWsHe3h4NGzbE8ePHcfv2bWzatAknT57E+/fvERAQgMOHD+PevXs4fvw4Tp8+DTc3txRtf0rhrXaUofDWCyIiIqKUkdzjqvR2TMXjRSL6Gubm5klO695/KKxyWGPR7Gl4eP8usplbwM3dE50CegMAHB0dMWrUKAwaNAj+/v7w8/PD0qVLk/W5xsbG2LdvH/r27Ys6derg48ePKFSoEGbPng1DQ0O8ePECfn5+CA0NhbW1NRo3boxRo0alRJNTHBNPREQ6wINaIiIiIqL050uJoaBFq5T/q1QqtPnxZ7T58eck6//666/49ddfNcoOHz6caF0R0fg7d+7c2LhxY6J116xZ89k49QkTT0REREREROkcL3qlP1xm9F/BxBMREVEGxoNaIiIiIkpLTDwRERERkc4xCUpERPTfxKfaERERERERERGRTjDxREREREREREREOsHEExERERERERER6QQTT0REREREREREpBNMPBERERERERERkU4w8URERERERERERDrBxBMREREREREREelEprQOgIiIiIiIiIgopTgP2pmqn7c9oFyqfl56wx5PRERERERERESkE0w8ERERERERERGlksqVK6NHjx7o1asXrKysYGdnhwULFiAiIgL+/v7Ili0b8ufPj927dyvzXL58GbVr14aZmRns7OzQrl07PH/+XJm+Z88elC9fHpaWlsiRIwfq1q2LW7duKdPv3r0LlUqFzZs3o0qVKsiSJQs8PT1x8uRJnbeXiSciIiIiIiIiolS0bNkyWFtb49SpU+jRowe6du2KZs2awdvbG+fOnUONGjXQrl07REZG4vXr16hatSqKFSuGM2fOYM+ePQgNDUXz5s2V94uIiECfPn1w5swZhISEwMDAAI0aNUJcXJzG5w4dOhT9+vXDhQsXUKBAAbRq1QofP37UaVs5xhMRERERERERUSry9PTEsGHDAACDBw/GxIkTYW1tjc6dOwMAhg8fjrlz5+LSpUs4cOAAihUrhvHjxyvzL168GE5OTvj3339RoEABNGnSROP9Fy9eDBsbG1y5cgXu7u5Keb9+/eDr6wsAGDVqFAoXLoybN2+iYMGCOmsrezwREREREREREaWiIkWKKP83NDREjhw54OHhoZTZ2dkBAMLCwnDx4kUcOnQIZmZmykudKFLfTnfjxg20atUKefPmhbm5OZydnQEA9+/fT/JzHRwclM/QJfZ4IiIiIiIiIiJKRUZGRhp/q1QqjTKVSgUAiIuLQ3h4OOrVq4dJkyZpvY86eVSvXj3kzp0bCxYsQM6cOREXFwd3d3dER0cn+bnxP0OXmHgiIiIiIiIiItJTxYsXx6ZNm+Ds7IxMmbTTOC9evMD169exYMECVKhQAQDwxx9/pHaYSeKtdkREREREREREeqp79+54+fIlWrVqhdOnT+PWrVvYu3cv/P39ERsbCysrK+TIkQPz58/HzZs3cfDgQfTp0yetw1Yw8UREREREREREpKdy5syJ48ePIzY2FjVq1ICHhwd69eoFS0tLGBgYwMDAAGvXrsXZs2fh7u6O3r1747fffkvrsBW81Y6IiIiIiIiIMoy7E3118r6XHr5Okfc5fPiwVtndu3e1ykRE+b+Liws2b96c5Hv6+PjgypUrSc7v7Oys8TcAWFpaapXpAns8ERERERERERGRTjDxREREREREREREOsHEExERERERERER6QQTT0REREREREREpBNMPBERERERERERkU4w8URERERERERERDrBxBMREREREREREekEE09ERERERERERKQTTDwREREREREREZFOMPFERERERERERJSO3L17FyqVChcuXEjrUL4oU1oHQERERERERESUYkZa6ORtiyRRfqnTvRT7jA4dOuD169fYunVrir1nWmOPJyIiIiIiIiIi0gkmnvTc7Nmz4ezsDFNTU5QuXRqnTp36bP2goCC4uroic+bMcHJyQu/evfHhw4dUipaIiIiIiIiIvmTjxo3w8PBA5syZkSNHDvj4+KB///5YtmwZtm3bBpVKBZVKhcOHDwMATp06hWLFisHU1BQlS5bE+fPn07YBX4G32umxdevWoU+fPggODkbp0qURFBSEmjVr4vr167C1tdWqv3r1agwaNAiLFy+Gt7c3/v33X3To0AEqlQqBgYFp0AIiIiIiIiIiiu/Jkydo1aoVJk+ejEaNGuHdu3c4duwY/Pz8cP/+fbx9+xZLliwBAGTPnh3h4eGoW7cuqlevjpUrV+LOnTvo2bNnGrci+Zh40mOBgYHo3Lkz/P39AQDBwcHYuXMnFi9ejEGDBmnVP3HiBMqVK4fWrVsDAJydndGqVSv89ddfqRo3ERERERERESXuyZMn+PjxIxo3bozcuXMDADw8PAAAmTNnRlRUFOzt7ZX6S5cuRVxcHBYtWgRTU1MULlwYDx8+RNeuXdMk/q/FW+30VHR0NM6ePQsfHx+lzMDAAD4+Pjh58mSi83h7e+Ps2bPK7Xi3b9/Grl27UKdOnSQ/JyoqCm/fvtV4EREREREREZFueHp6olq1avDw8ECzZs2wYMECvHr1Ksn6V69eRZEiRWBqaqqUlS1bNjVCTRFMPOmp58+fIzY2FnZ2dhrldnZ2ePr0aaLztG7dGqNHj0b58uVhZGSEfPnyoXLlyhgyZEiSnzNhwgRYWFgoLycnpxRtBxERERERERH9n6GhIfbv34/du3ejUKFCmDlzJlxdXXHnzp20Dk0nmHjKQA4fPozx48djzpw5OHfuHDZv3oydO3dizJgxSc4zePBgvHnzRnk9ePAgFSMmIiIiIiIi+u9RqVQoV64cRo0ahfPnz8PY2BhbtmyBsbExYmNjNeq6ubnh0qVLGg8O+/PPP1M75G/GMZ70lLW1NQwNDREaGqpRHhoaqnGvZ3y//vor2rVrh06dOgH4dI9oREQEunTpgqFDh8LAQDvPaGJiAhMTk5RvABERERERERFp+euvvxASEoIaNWrA1tYWf/31F549ewY3Nzd8+PABe/fuxfXr15EjRw5YWFigdevWGDp0KDp37ozBgwfj7t27mDJlSlo3I9nY40lPGRsbo0SJEggJCVHK4uLiEBISkuS9nJGRkVrJJUNDQwCAiOguWCIiIiIiIiJKFnNzcxw9ehR16tRBgQIFMGzYMEydOhW1a9dG586d4erqipIlS8LGxgbHjx+HmZkZfv/9d/z9998oVqwYhg4dikmTJqV1M5KNPZ70WJ8+fdC+fXuULFkSXl5eCAoKQkREhPKUOz8/Pzg6OmLChAkAgHr16iEwMBDFihVD6dKlcfPmTfz666+oV6+ekoAiIiIiIiIiytBGvtHJ2156+DpF3sfNzQ179uxJdJqNjQ327dunVV6mTBlcuHBBoyy9dDBh4kmPtWjRAs+ePcPw4cPx9OlTFC1aFHv27FEGHL9//75GD6dhw4ZBpVJh2LBhePToEWxsbFCvXj2MGzcurZpARERERERERP9hTDzpuYCAAAQEBCQ67fDhwxp/Z8qUCSNGjMCIESNSITIiIiIiIiIios/jGE9ERERERERERKQTTDwREREREREREZFOMPFEREREREREROlSehlgO71Kie+XYzwREREREX0j50E7k1337kRfHUZCRPTfYmRkBACIjIxE5syZ0ziajCsyMhLA/7/vb8HEExERERERERGlK4aGhrC0tERYWBgAIEuWLFCpVDr9TPkYney6Hz580GEkuiciiIyMRFhYGCwtLWFoaPjN78XEExERERERERGlO/b29gCgJJ90LezV+2TXNX6fMXphWVpaKt/zt2LiiYiIiIiIiIjSHZVKBQcHB9ja2iImJkbnn9dp8+Fk1w3pW1lncaQWIyOj7+rppMbEExERERERERGlW4aGhimSIPmSR+9ik13X1NRUh5GkL3yqHRERERERERER6QQTT0REREREREREpBNMPBERERERERERkU4w8URERERERERERDrBxBMREREREREREekEE09ERERERERERKQTTDwREREREREREZFOMPFEREREREREREQ6wcQTERERERERERHpBBNPRERERERERESkE0w8ERERERERERGRTjDxREREREREREREOsHEExERERERERER6QQTT0REREREREREpBNMPBERERERERERkU4w8URERERERERERDrBxBMREREREREREekEE09ERERERERERKQTTDwREREREREREZFOMPFEREREREREREQ6wcQTERERERERERHpBBNPRERERERERESkE0w8ERERERERERGRTjDxREREREREREREOsHEExERERERERER6QQTT0REREREREREpBNMPBERERERERERkU4w8URERERERERERDrBxBMREREREREREekEE09ERERERERERKQTTDwREREREREREZFOMPFEREREREREREQ6wcQTERERERERERHpBBNPRERERERERESkE0w8ERERERERERGRTjDxREREREREREREOsHEk56bPXs2nJ2dYWpqitKlS+PUqVOfrf/69Wt0794dDg4OMDExQYECBbBr165UipaIiIiIiIiI6P8ypXUAlLR169ahT58+CA4ORunSpREUFISaNWvi+vXrsLW11aofHR2N6tWrw9bWFhs3boSjoyPu3bsHS0vL1A+eiIiIiIiIiP7zmHjSY4GBgejcuTP8/f0BAMHBwdi5cycWL16MQYMGadVfvHgxXr58iRMnTsDIyAgA4OzsnJohExEREREREREpeKudnoqOjsbZs2fh4+OjlBkYGMDHxwcnT55MdJ7t27ejbNmy6N69O+zs7ODu7o7x48cjNjY2tcImIiIiIiIiIlKwx5Oeev78OWJjY2FnZ6dRbmdnh2vXriU6z+3bt3Hw4EG0adMGu3btws2bN9GtWzfExMRgxIgRic4TFRWFqKgo5e+3b9+mXCOIiIiIiIiI6D+NPZ4ykLi4ONja2mL+/PkoUaIEWrRogaFDhyI4ODjJeSZMmAALCwvl5eTklIoRExEREREREVFGxsSTnrK2toahoSFCQ0M1ykNDQ2Fvb5/oPA4ODihQoAAMDQ2VMjc3Nzx9+hTR0dGJzjN48GC8efNGeT148CDlGkFERERERERE/2lMPOkpY2NjlChRAiEhIUpZXFwcQkJCULZs2UTnKVeuHG7evIm4uDil7N9//4WDgwOMjY0TncfExATm5uYaLyIiIiIiIiKilMDEUwp68OABHj58qPx96tQp9OrVC/Pnz/+m9+vTpw8WLFiAZcuW4erVq+jatSsiIiKUp9z5+flh8ODBSv2uXbvi5cuX6NmzJ/7991/s3LkT48ePR/fu3b+vYURERERERERE34CDi6eg1q1bo0uXLmjXrh2ePn2K6tWro3Dhwli1ahWePn2K4cOHf9X7tWjRAs+ePcPw4cPx9OlTFC1aFHv27FEGHL9//z4MDP6fO3RycsLevXvRu3dvFClSBI6OjujZsycGDhyYou0kIiIiIiIiIkoOJp5S0OXLl+Hl5QUAWL9+Pdzd3XH8+HHs27cPP//881cnngAgICAAAQEBiU47fPiwVlnZsmXx559/fvXnEBERERERERGlNN5ql4JiYmJgYmICADhw4ADq168PAChYsCCePHmSlqEREREREREREaU6Jp5SUOHChREcHIxjx45h//79qFWrFgDg8ePHyJEjRxpHR0RERERERESUuph4SkGTJk3CvHnzULlyZbRq1Qqenp4AgO3btyu34BERERERERER/VdwjKcUVLlyZTx//hxv376FlZWVUt6lSxdkyZIlDSMjIiIiIiIiIkp97PGUwkQEZ8+exbx58/Du3TsAgLGxMRNPRERERERERPSfwx5PKejevXuoVasW7t+/j6ioKFSvXh3ZsmXDpEmTEBUVheDg4LQOkYiIiIiIiIgo1bDHUwrq2bMnSpYsiVevXiFz5sxKeaNGjRASEpKGkRERERERERERpT72eEpBx44dw4kTJ2BsbKxR7uzsjEePHqVRVEREREREREREaYM9nlJQXFwcYmNjtcofPnyIbNmypUFERERERERERERph4mnFFSjRg0EBQUpf6tUKoSHh2PEiBGoU6dO2gVGRERERERERJQGeKtdCpo6dSpq1qyJQoUK4cOHD2jdujVu3LgBa2trrFmzJq3DIyIiIiIiIiJKVUw8paBcuXLh4sWLWLt2LS5duoTw8HD8+OOPaNOmjcZg40RERERERERE/wVMPKWwTJkyoW3btmkdBhERERERERFRmmPiKQUtX778s9P9/PxSKRIiIiIiIiIiorTHxFMK6tmzp8bfMTExiIyMhLGxMbJkycLEExERERERERH9p/Cpdino1atXGq/w8HBcv34d5cuX5+DiRERERERERPSfw8STjrm4uGDixIlavaGIiIiIiIiIiDI6Jp5SQaZMmfD48eO0DoOIiIiIiIiIKFVxjKcUtH37do2/RQRPnjzBrFmzUK5cuTSKioiIiIiIiIgobTDxlIIaNmyo8bdKpYKNjQ2qVq2KqVOnpk1QRERERERERERphImnFBQXF5fWIRARERERERER6Q2O8URERERERERERDrBHk/fqU+fPsmuGxgYqMNIiIiIiIiIiIj0CxNP3+n8+fPJqqdSqXQcCRERERERERGRfmHi6TsdOnQorUMgIiIiIiIiItJLHOOJiIiIiIiIiIh0gj2eUtiZM2ewfv163L9/H9HR0RrTNm/enEZRERERERERERGlPvZ4SkFr166Ft7c3rl69ii1btiAmJgb//PMPDh48CAsLi7QOj4iIiIiIiIgoVTHxlILGjx+PadOm4ffff4exsTGmT5+Oa9euoXnz5vjhhx/SOjwiIiIiIiIiolTFxFMKunXrFnx9fQEAxsbGiIiIgEqlQu/evTF//vw0jo6IiIiIiIiIKHUx8ZSCrKys8O7dOwCAo6MjLl++DAB4/fo1IiMj0zI0IiIiIiIiIqJUx8RTClAnmCpWrIj9+/cDAJo1a4aePXuic+fOaNWqFapVq5aWIRIRERERERERpTo+1S4FFClSBKVKlULDhg3RrFkzAMDQoUNhZGSEEydOoEmTJhg2bFgaR0lERERERERElLqYeEoBR44cwZIlSzBhwgSMGzcOTZo0QadOnTBo0KC0Do2IiIiIiIiIKM3wVrsUUKFCBSxevBhPnjzBzJkzcffuXVSqVAkFChTApEmT8PTp07QOkYiIiIiIiIgo1THxlIKyZs0Kf39/HDlyBP/++y+aNWuG2bNn44cffkD9+vXTOjwiIiIiIiIiolTFxJOO5M+fH0OGDMGwYcOQLVs27Ny5M61DIiIiIiIiIiJKVRzjSQeOHj2KxYsXY9OmTTAwMEDz5s3x448/pnVYRERERERERESpiomnFPL48WMsXboUS5cuxc2bN+Ht7Y0ZM2agefPmyJo1a1qHR0RERERERESU6ph4SgG1a9fGgQMHYG1tDT8/P3Ts2BGurq5pHRYRERERERERUZpi4ikFGBkZYePGjahbty4MDQ3TOhwiIiIiIiIiIr3AxFMK2L59e1qHQERERET6bqTFV9R9o7s4iIiIUhGfakdERERERERERDrBxBMREREREREREekEE096bvbs2XB2doapqSlKly6NU6dOJWu+tWvXQqVSoWHDhroNkIiIiIiIiIgoCUw86bF169ahT58+GDFiBM6dOwdPT0/UrFkTYWFhn53v7t276NevHypUqJBKkRIRERERERERaWPiSY8FBgaic+fO8Pf3R6FChRAcHIwsWbJg8eLFSc4TGxuLNm3aYNSoUcibN28qRktEREREREREpImJJz0VHR2Ns2fPwsfHRykzMDCAj48PTp48meR8o0ePhq2tLX788cfUCJOIiIiIiIiIKEmZ0joAStzz588RGxsLOzs7jXI7Oztcu3Yt0Xn++OMPLFq0CBcuXEj250RFRSEqKkr5++3bt98ULxERERERERFRQuzxlEG8e/cO7dq1w4IFC2BtbZ3s+SZMmAALCwvl5eTkpMMoiYiIiIiIiOi/hD2e9JS1tTUMDQ0RGhqqUR4aGgp7e3ut+rdu3cLdu3dRr149pSwuLg4AkClTJly/fh358uXTmm/w4MHo06eP8vfbt2+ZfCIiIiIiIiKiFMHEk54yNjZGiRIl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RBxSt27dmDt3rv1xTEwMXbt2vWu9wYMHs3TpUubNm8f+/fspW7YsjRs35qeffgJuJwxat25NixYtOHjwIN27d2fIkCE59vHtt9/SpEkTAgMDOXz4MJ988glbt26lX79+AOzdu5fQ0FBGjBjBN998w5o1a3j++ed/NfbDhw9z9epVatWqZV928OBBjh07xsCBAzGbc34Eq1atGg0bNmTx4sV/+PW5cuUK//nPf6hRowZ79+5lzZo1pKSk0K5dOwCSk5N55ZVX6NatG8ePH2fz5s20bt0awzB48803adeuHU2aNCE5OZnk5GTq1q171zEuXrzISy+9xL///W8OHTrEjBkzmDNnDiNHjsyx3rx58yhYsCC7du0iKiqKESNGsH79+lzjttlsxMXF0bFjR0qUKHHX84UKFbKPuAoODmbv3r188cUX7NixA8MweOmll8jIyLCvf/PmTSZPnkxcXBxr1qxh8+bNtGrVilWrVrFq1SoWLFjARx99xJIlS3Ic5/3336datWocOHCAIUOG8Prrr/9qzBkZGTRu3Bg3Nze2bNnCtm3bKFSoEE2aNMFqtVKxYkU++OAD+vbty7lz57hw4QK9e/dm3LhxPPnkk3ftb9KkSfj7+9OjRw/761+6dOm7fucB5s6dy/PPP0/ZsmXty2rXrs2WLVtyjVVERMThGCIiIiIOJCgoyAgICDAuXbpkuLi4GGfOnDHOnDljuLq6Gj/++KMREBBgBAUFGYZhGNevXzecnZ2NRYsW2be3Wq1GiRIljKioKMMwDOOtt94ynnzyyRzHCA8PNwAjNTXVMAzDCAkJMXr27JljnS1bthhms9lIS0szli5dari7uxvXrl37Q+ewbNkyw2KxGDabzb4sLi7OAIwDBw7kuk1oaKiRP39+wzAM4/Tp03etm5qaagDGpk2bDMMwjPfee89o1KhRjn2cP3/eAIxvvvnG2LdvnwEYZ86cyfV42a/znX553IiICKNChQo5zmPatGlGoUKFjKysLMMwDKN+/frGs88+m2M///73v43w8PBcj5uSkmIAxoQJE3J9PtuJEycMwNi2bZt92eXLl438+fMbn376qWEYhjF37lwDME6dOmVfp1evXkaBAgWMn3/+2b6scePGRq9eveyPH3/8caNJkyY5jte+fXujadOm9seAsWzZMsMwDGPBggV3vQ7p6elG/vz5jbVr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", + "text/plain": [ + "
    " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Grouped bar chart\n", + "metrics = ['mean', 'std']\n", + "x = np.arange(len(answer_rel_df['mode'])) # Label locations\n", + "width = 0.2 # Bar width\n", + "fig, ax = plt.subplots(figsize=(12, 6))\n", + "for i, metric in enumerate(metrics):\n", + " ax.bar(x + i * width, answer_rel_df[metric], width, label=metric)\n", + "ax.set_xticks(x + width * 1.5)\n", + "ax.set_xticklabels(answer_rel_df['mode'] + ' (' + answer_rel_df['question_complexity'] + ')', rotation=45, ha='right')\n", + "ax.set_xlabel('Modes (Question Complexity)')\n", + "ax.set_ylabel('Values')\n", + "ax.set_title('Grouped Bar Chart of Answer Relevancy Metrics by Mode and Question Complexity')\n", + "ax.legend(title=\"Metrics\")\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1.All modes score fairly for answer relevancy except \" graph + vector \" mode for reasoning questions" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 3. Answer Correctness\n", + "\n", + "Measures answer correctness compared to ground truth as a combination of factuality and semantic similarity." + ] + }, + { + "cell_type": "code", + "execution_count": 96, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
    \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
    modequestion_complexitymeanminmaxstd
    0entity search+vectormulti_context0.7424960.5234710.9922690.170004
    1entity search+vectorreasoning0.8035360.5657110.9436290.147004
    2entity search+vectorsimple0.5377660.1726750.7334100.251963
    3fulltextmulti_context0.8033990.4373950.9955870.208676
    4fulltextreasoning0.8533490.6190320.9967040.187401
    5fulltextsimple0.6723180.1753730.9401640.339199
    6global search+vector+fulltextmulti_context0.7355390.6095250.9091840.123181
    7global search+vector+fulltextreasoning0.7278430.4883640.8461430.162029
    8global search+vector+fulltextsimple0.3945940.1721250.6658700.250464
    9graph+vectormulti_context0.7421800.4913980.9181700.188076
    10graph+vectorreasoning0.8584120.6700620.9965560.137474
    11graph+vectorsimple0.5594330.1749660.8452230.300916
    12graph+vector+fulltextmulti_context0.7367840.4372160.9902460.237939
    13graph+vector+fulltextreasoning0.7869990.4557120.9466830.190876
    14graph+vector+fulltextsimple0.6436410.1750820.9343100.339174
    15vectormulti_context0.8133150.5442150.9912020.156961
    16vectorreasoning0.6771240.4754650.8232990.126854
    17vectorsimple0.5845350.1753240.8178120.292301
    \n", + "
    " + ], + "text/plain": [ + " mode question_complexity mean min \\\n", + "0 entity search+vector multi_context 0.742496 0.523471 \n", + "1 entity search+vector reasoning 0.803536 0.565711 \n", + "2 entity search+vector simple 0.537766 0.172675 \n", + "3 fulltext multi_context 0.803399 0.437395 \n", + "4 fulltext reasoning 0.853349 0.619032 \n", + "5 fulltext simple 0.672318 0.175373 \n", + "6 global search+vector+fulltext multi_context 0.735539 0.609525 \n", + "7 global search+vector+fulltext reasoning 0.727843 0.488364 \n", + "8 global search+vector+fulltext simple 0.394594 0.172125 \n", + "9 graph+vector multi_context 0.742180 0.491398 \n", + "10 graph+vector reasoning 0.858412 0.670062 \n", + "11 graph+vector simple 0.559433 0.174966 \n", + "12 graph+vector+fulltext multi_context 0.736784 0.437216 \n", + "13 graph+vector+fulltext reasoning 0.786999 0.455712 \n", + "14 graph+vector+fulltext simple 0.643641 0.175082 \n", + "15 vector multi_context 0.813315 0.544215 \n", + "16 vector reasoning 0.677124 0.475465 \n", + "17 vector simple 0.584535 0.175324 \n", + "\n", + " max std \n", + "0 0.992269 0.170004 \n", + "1 0.943629 0.147004 \n", + "2 0.733410 0.251963 \n", + "3 0.995587 0.208676 \n", + "4 0.996704 0.187401 \n", + "5 0.940164 0.339199 \n", + "6 0.909184 0.123181 \n", + "7 0.846143 0.162029 \n", + "8 0.665870 0.250464 \n", + "9 0.918170 0.188076 \n", + "10 0.996556 0.137474 \n", + "11 0.845223 0.300916 \n", + "12 0.990246 0.237939 \n", + "13 0.946683 0.190876 \n", + "14 0.934310 0.339174 \n", + "15 0.991202 0.156961 \n", + "16 0.823299 0.126854 \n", + "17 0.817812 0.292301 " + ] + }, + "execution_count": 96, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "answer_cor_df = eval_df.groupby(['mode', 'question_complexity']).agg({\n", + " 'answer_correctness': ['mean', 'min', 'max', 'std']\n", + "}).reset_index()\n", + "answer_cor_df.columns = ['mode', 'question_complexity', 'mean', 'min', 'max', 'std']\n", + "answer_cor_df" + ] + }, + { + "cell_type": "code", + "execution_count": 97, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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zhyN+Xfs2IFLly4p6/1rmZmZYeDAgbh06RIGDhyY7HXX8uXLcfToUQAf1tXRo0eVMQOBD8tt3rx5cHFx+Wh32C9x5MgRjTEe7969i82bN6NGjRopJslSu84A4O+//8bEiRPRq1cv9O3bF/3798eMGTO0xhRM6lPngKCgIKhUKvTs2RM3btz4rDHgiDIDtngiokzF1dUVK1euRFBQENzc3NCqVSt4e3tDRHDz5k2sXLkSBgYGWuM5JadevXqoUqUKhgwZglu3bsHb2xu7d+/G5s2b0atXL42Bmzt27Ihx48ahY8eOKF26NP74449kEyhqN2/eRP369VGzZk0cOXIEy5cvR8uWLZUkT6FChTB69GgMHjwYt27dQsOGDWFhYYGbN29i48aN6Ny5M/r164ds2bJh9OjR+O6771C1alU0b94cN2/exOLFiz9rjKd79+4pv57GxsbizJkzmDt3LmxtbZUbGEtLS2WMibi4ODg7O2P37t24efNmqr8nJTY2Nti4cSNq166NEiVKoHXr1srgnydPnsSqVatQrly5z/7cunXrYtSoUQgJCYGfnx/OnTuHFStWfNayKVGiBAwNDTF+/Hi8ePECJiYmqFq1aorjevz888+oVasWypUrhw4dOuDNmzeYPn06rKysMGLEiM+uw99//41r164hNDQ02fednZ1RqlQprFixAgMHDkz157569Qp58uRBkyZN4O3tDXNzc+zduxfHjh3DpEmTNMr6+/tj3LhxsLKygpeXF4APiQ43NzdcuXIF7dq10yhfqVIlfPfddwgLC8Pp06dRo0YNZMuWDVevXsXatWsxdepUNGnS5PMWxP9r3rw5zp07hzFjxuDUqVMICgpC/vz58eTJE+zcuRMRERHKeDmdO3fG3Llz0a5dO5w4cQIuLi5Yt24dDh06hClTpnz2gPaJpXYfNTAwwOzZs1GvXj2UKFECISEhcHJywuXLl3HhwgXs2rULAJTtvUePHggMDIShoSFatGjxWTHNnDkTFSpUgJeXFzp16oSCBQsiMjISR44cwb///oszZ84A+NBto3LlyvDx8UHOnDlx/PhxrFu3TtnG/vnnH1SrVg3NmjWDh4cHjIyMsHHjRkRGRn52TADQs2fPT5Zp06YN1qxZg++//x779+9H+fLlER8fj8uXL2PNmjXYtWsXSpcuDeDDstq7dy/Cw8ORO3du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pXHq1KmMrcBnYFc7IiIiIiIiIqJ08uDBAwQFBWHChAlo1KgRXr16hYMHDyI4OBh37tzBy5cvsXjxYgBAzpw58fr1a9StWxfVq1fH8uXLcfPmTfTs2TODa5F6TDwREREREREREaWTBw8e4P379/j222+RP39+AICXlxcAIHv27Hj37h0cHR2V8kuWLEFCQgIWLlwIU1NTFCtWDP/++y+6dOmSIfF/Lna1IyIiIiIiIiJKJ97e3qhWrRq8vLzQtGlTzJ8/H8+ePUux/KVLl1C8eHGYmpoq08qVK5ceoaYJJp6IiIiIiIiIiNKJoaEh9uzZgx07dsDDwwPTp0+Hm5sbbt68mdGh6QQTT0RERERERERE6UilUqF8+fIYOXIkTp06BWNjY2zcuBHGxsaIj4/XKFu0aFGcPXsWb9++Vab99ddf6R3yF2PiiYiIiIiIiIgonfz9998YO3Ysjh8/jjt37mDDhg149OgRihYtChcXF5w9exZXrlzB48ePERcXh5YtW0KlUqFTp064ePEitm/fjokTJ2Z0NVKNiSciIiIiIiIionRiaWmJP/74A7Vr10aRIkUwdOhQTJo0CbVq1UKnTp3g5uaG0qVLw87ODocOHYK5uTl+++03nDt3DiVLlsSQIUMwfvz4jK5GqvGpdkRERERERESUdYx4kdERfFTRokWxc+fOZN+zs7PD7t27taaXLVsWp0+f1pgmIroIL82xxRMREREREREREekEE09ERERERERERKQTTDwREREREREREZFOMPFEREREREREREQ6wcHFiYiIiIiIiChNuAzaluqyt8bV+ervyywDbGdWabF8mXgiIiJC6i+S0uICiYiIiIi+TrZs2QAAMTExyJ49ewZHk3XFxMQA+N/y/hJMPBERERERERFRpmJoaAhra2tERUUBAMzMzKBSqTI4qqxDRBATE4OoqChYW1vD0NDwiz+LiSciIiIiIiIiynQcHR0BQEk+UdqztrZWlvOXYuKJiIiIiIiIiDIdlUoFJycn2NvbIy4uLqPDyXKyZcv2VS2d1Jh4IiIiIiIiIqJMy9DQME0SJKQbBhkdABERERERERERZU1MPBERERERERERkU4w8URERERERERERDrBxBMREREREREREekEBxcnIiIiIiIiveUyaFuqy94aV0eHkRDRl2CLJyIiIiIiIiIi0gkmnoiIiIiIiIiISCeYeCIiIiIiIiIiIp1g4omIiIiIiIiIiHSCiSciIiIiIiIiItIJJp6IiIiIiIiIiEgnmHgiIiIiIiIiIiKdYOKJiIiIiIiIiIh0goknPTdz5ky4uLjA1NQUZcqUwdGjRz9a/vnz5+jWrRucnJxgYmKCIkWKYPv27ekULRERERERERHR/xhldACUsl9//RV9+vTBnDlzUKZMGUyZMgWBgYG4cuUK7O3ttcrHxsaievXqsLe3x7p16+Ds7Izbt2/D2to6/YMnIiIiIiIiov88Jp70WHh4ODp16oSQkBAAwJw5c7Bt2zYsWrQIgwYN0iq/aNEiPH36FIcPH0a2bNkAAC4uLukZMhERERERERGRgl3t9FRsbCxOnDiBgIAAZZqBgQECAgJw5MiRZOfZsmULypUrh27dusHBwQGenp4YO3Ys4uPj0ytsIiIiIiIiIiIFWzzpqcePHyM+Ph4ODg4a0x0cHHD58uVk57lx4wb27duHVq1aYfv27bh27Rq6du2KuLg4DB8+PNl53r17h3fv3il/v3z5Mu0qQURERERERET/aWzxlIUkJCTA3t4e8+bNg4+PD5o3b44hQ4Zgzpw5Kc4TFhYGKysr5ZU3b950jJiIiIiIiIiIsjImnvSUra0tDA0NERkZqTE9MjISjo6Oyc7j5OSEIkWKwNDQUJlWtGhRPHz4ELGxscnOM3jwYLx48UJ53b17N+0qQURERERERET/aUw86SljY2P4+PggIiJCmZaQkICIiAiUK1cu2XnKly+Pa9euISEhQZn2zz//wMnJCcbGxsnOY2JiAktLS40XEREREREREVFaYOJJj/Xp0wfz58/H0qVLcenSJXTp0gXR0dHKU+6Cg4MxePBgpXyXLl3w9OlT9OzZE//88w+2bduGsWPHolu3bhlVBSIiIiIiIiL6D+Pg4nqsefPmePToEYYNG4aHDx+iRIkS2LlzpzLg+J07d2Bg8L/cYd68ebFr1y707t0bxYsXh7OzM3r27ImBAwdmVBWIiIiIiIiI6D+MiSc9FxoaitDQ0GTfO3DggNa0cuXK4a+//tJxVERERERERET/LS6DtqW67K1xdXQYSebCrnZERERERERERKQTTDwREREREREREZFOMPFEREREREREREQ6wcQTERERERERERHpBBNPRERERERERESkE0w8ERERERERERGRThhl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iIiIiHSCiSciIiIiIiIiItIJJp6IiIiIiIiIiEgnmHgiIiIiIiIiIiKdYOKJiIiIiIiIiIh0goknIiIiIiIiIiLSCaOMDoCIKFVGWH1G2Re6i4OISF/wuEhERESZAFs8ERERERERERGRTjDxREREREREREREOsHEExERERERERER6QTHeCIiIiIiIkoOx1IjIvpqbPFEREREREREREQ6wcQTERERERERERHpBBNPRERERERERESkE0w8ERERERERERGRTjDxREREREREREREOsHEExERERERERER6QQTT0REREREREREpBNMPOm5mTNnwsXFBaampihTpgyOHj2aYtn58+fD398fNjY2sLGxQUBAwEfLExERERERERHpklFGB0Ap+/XXX9GnTx/MmTMHZcqUwZQpUxAYGIgrV67A3t5eq/yBAwcQFBQEPz8/mJqaYvz48ahRowYuXLgAZ2fnDKgBEaXKCKvPKPtCd3EQERERERGlMbZ40mPh4eHo1KkTQkJC4OHhgTlz5sDMzAyLFi1KtvyKFSvQtWtXlChRAu7u7liwYAESEhIQERGRzpETERERERERETHxpLdiY2Nx4sQJBAQEKNMMDAwQEBCAI0eOpOozYmJiEBcXh5w5c6ZY5t27d3j58qXGi4iIiIiIiIgoLTDxpKceP36M+Ph4ODg4aEx3cHDAw4cPU/UZAwcORO7cuTWSV0mFhYXByspKeeXNm/er4iYiIiIiIiIiUmPiKYsaN24cVq9ejY0bN8LU1DTFcoMHD8aLFy+U1927d9MxSiIiIiIiIiLKyji4uJ6ytbWFoaEhIiMjNaZHRkbC0dHxo/NOnDgR48aNw969e1G8ePGPljUxMYGJiclXx0tERERERERElBQTT3rK2NgYPj4+iIiIQMOGDQFAGSg8NDQ0xfkmTJiAMWPGYNeuXShdunQ6RUtERERERJkGn6hLROmIiSc91qdPH7Rt2xalS5eGr68vpkyZgujoaISEhAAAgoOD4ezsjLCwMADA+PHjMWzYMKxcuRIuLi7KWFDm5uYwNzfPsHoQ0X8UL2qJ6Evx+EFERJRlMPGkx5o3b45Hjx5h2LBhePjwIUqUKIGdO3cqA47fuXMHBgb/G6Zr9uzZiI2NRZMmTTQ+Z/jw4RgxYkR6hk5ERERERERExMSTvgsNDU2xa92BAwc0/r5165buAyIi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AgEBAfz8888MHz6coKAg4NbMdxaLRY3ERURERERE7Izu0ETEruTkwp2cnLh58yZWqxWz2UxGRgalS5dm3Lhx/PDDDyxcuJDY2FgALBYLhmEo6SQiIiIiImJndJcmInYlZya7Vq1asX//fiZMmACAo6MjAFarlWbNmmEYBnPnzsVqtebaTkREREREROyHejyJiF2qXr06c+bMoVevXly/fp0OHTpQtGhRpk2bRr169WjdujVVq1blm2++oVGjRvkdroiIiIiIiORBPZ5ExK4tXbqUfv36UaBAAQzDwNPTk23btpGSksJ///tflixZwlNPPZXfYYqIiIiIiEgeNOJJROxaQEAAzzzzDOfOnSMjI4P69etjNpuJiorCYrHg6emZ3yGKiIiIiIjIXWjEk4g8VBITE5kwYQKrV69m/fr11KxZM79DEhERERERkbvQiCcReWhkZmZitVrx9PQkISGBqlWr5ndIIiIiIiIi8js04klEHjoZGRm2We5ERERERETEfinxJCIiIiIiIiIi94U5vwMQEREREREREZFHkxJPIiIiIiIiIiJyXyjxJCIiIiIiIiIi94USTyIiIiIiIiIicl8o8SQiIiIiIiIiIveFEk8iIiLyj7Np0yZMJhOXL1++r8fp0qULY8eOva/HuJdOnz6NyWTiwIED+R1KvjOZTCxfvvye7S8oKIhWrVr9T/uwWq34+PiwZ8+eexOUiIjIA6DEk4iIiNiVoKAgTCYTffr0ueO51157DZPJRFBQ0IMP7C86ePAgq1evJiQkJNfyxMRE2rdvj4eHB05OTlSsWJGIiAhu3LjxQOPLKxHi7e1NcnIy1apVu+/Hv3r1KsOHD6dy5co4OztTokQJGjVqRFxcHIZh3PfjP2hTpkwhJibG9rhhw4YMGjToL+2jQIECvPHGG4SFhd3b4ERERO4jJZ5ERETE7nh7exMbG0taWppt2c2bN/nkk08oW7ZsPkb2502bNo127dpRpEgR27IdO3ZQt25drFYrX375JcePH2fMmDHExMTw3//+F6vVmo8Rg8VioUSJEjg4ONzX41y+fJl69eqxYMEC3nzzTfbt28c333xDhw4dGDp0KFeuXLmvx88Pbm5uuLu7/8/76dSpE1u2bCExMfF/D0pEROQBUOJJRERE7E6tWrXw9vYmLi7OtiwuLo6yZcvi6+uba9309HRCQkLw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EitWrGDEiBF5Nkj/K8aMGYO3tzd169ZlwYIFHD16lBMnThAdHY2vry/Xrl2jQoUK+Pv707NnT7Zs2cLBgwfp3LkzpUuXxt/f/28fO8fWrVuJjIzk+PHjTJ8+nc8//5yBAwfmuW6nTp147LHH8Pf3Z/PmzZw6dYpNmzYREhLC+fPngVu/Z97e3rz11ltMmjSJrKws3njjjbse38fHh507d3L69GkuXbpkS0ZaLBaCgoJ48803qVChwh0lgQCbN2+mcePG//NrICIi8iAo8SQiIiJ2zdXVFVdX17s+P378eAICAujSpQu1atXi5MmTxMfH23oZlS1blqVLl7J8+XJq1KhBVFQUY8eOzbWPp556ioSEBI4fP85zzz2Hr68vERERtlnX3N3diYuL4z//+Q9VqlQhKiqKxYsXU7Vq1bvG1aNHjztKs+rXr8+OHTuwWCw0a9aMxx9/nPbt2+Pv78/KlStzJdeio6PJzMzk6aefZtCgQXfMJFeqVCm2bt1KVlYWjRs3pnr16gwaNAh3d3fMZjOurq588803vPTSS1SsWJG33nqLiRMn0qxZMwB69uxJpUqVqF27Nh4eHrlGjeUoXbo0q1evZteuXdSoUYM+ffoQHBx8RxLsrypWrBg7duygc+fOjB49Gl9fX5577jkWL17Me++9ZxtFNG/ePJ5++mlatGiBn58fhmGwevXqO0rp/o4hQ4awZ88efH19GT16NJMmTcpzVB3c6iP1zTffULZsWdq0aUOVKlUIDg7m5s2buLq6smDBAtsMeg4ODhQuXJiFCxcye/Zs1qxZk+c+33jjDSwWC08++SQeHh6cPXvW9lxwcDBWqzXPWRy3b9/OlStXaNu27f/8GoiIiDwIJuPPdngUERERkT8tLS2NSpUq8emnn+Y5agUgOzub4OBg4uPjSUhIsPWBkvvLx8eHQYMGMWjQoPwOJU+bN2/mxRdf5Ny5c3h5eeV6rkOHDtSoUYPw8PB8ik5EROSv0YgnERERkfugYMGCLFiwgEuXLt11HbPZzNy5cwkLC2Pz5s0PMDqxR+np6Zw/f56RI0fSrl27O5JOVquV6tWr8/rrr+dThCIiIn+dRjyJiIiIyD+KvY54iomJITg4mJo1a/LFF19QunTp/A5JRETkf6bEk4iIiIiIiIiI3BcqtRMRERERERERkftCiScREREREREREbkvlHgSEREREREREZH7QoknERERERERERG5L5R4EhERERERERGR+0KJJxERERERERERuS+UeBIRERERERERkftCiScREREREREREbkvlHgSEREREREREZH74v8BXmi8mV0IDLUAAAAASUVORK5CYII=", + "text/plain": [ + "
    " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Grouped bar chart\n", + "metrics = ['mean', 'std']\n", + "x = np.arange(len(answer_cor_df['mode'])) # Label locations\n", + "width = 0.2 # Bar width\n", + "fig, ax = plt.subplots(figsize=(12, 6))\n", + "for i, metric in enumerate(metrics):\n", + " ax.bar(x + i * width, answer_cor_df[metric], width, label=metric)\n", + "ax.set_xticks(x + width * 1.5)\n", + "ax.set_xticklabels(answer_cor_df['mode'] + ' (' + answer_cor_df['question_complexity'] + ')', rotation=45, ha='right')\n", + "ax.set_xlabel('Modes (Question Complexity)')\n", + "ax.set_ylabel('Values')\n", + "ax.set_title('Grouped Bar Chart of Answer Correctness Metrics by Mode and Question Complexity')\n", + "ax.legend(title=\"Metrics\")\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. All modes struggle on simple questions" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 4. Context Precision\n", + "\n", + "Context Precision is a metric that evaluates whether all of the ground-truth relevant items present in the contexts are ranked higher or not." + ] + }, + { + "cell_type": "code", + "execution_count": 98, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
    \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
    modequestion_complexitymeanminmaxstd
    0entity search+vectormulti_context0.8000000.01.00.447214
    1entity search+vectorreasoning0.8000000.01.00.447214
    2entity search+vectorsimple0.5000000.01.00.577350
    3fulltextmulti_context0.8333330.01.00.408248
    4fulltextreasoning1.0000001.01.00.000000
    5fulltextsimple1.0000001.01.00.000000
    6global search+vector+fulltextmulti_context0.8000000.01.00.447214
    7global search+vector+fulltextreasoning0.5000000.01.00.577350
    8global search+vector+fulltextsimple0.6666670.01.00.577350
    9graph+vectormulti_context0.8333330.01.00.408248
    10graph+vectorreasoning1.0000001.01.00.000000
    11graph+vectorsimple1.0000001.01.00.000000
    12graph+vector+fulltextmulti_context0.8333330.01.00.408248
    13graph+vector+fulltextreasoning1.0000001.01.00.000000
    14graph+vector+fulltextsimple1.0000001.01.00.000000
    15vectormulti_context0.8333330.01.00.408248
    16vectorreasoning1.0000001.01.00.000000
    17vectorsimple0.7500000.01.00.500000
    \n", + "
    " + ], + "text/plain": [ + " mode question_complexity mean min max \\\n", + "0 entity search+vector multi_context 0.800000 0.0 1.0 \n", + "1 entity search+vector reasoning 0.800000 0.0 1.0 \n", + "2 entity search+vector simple 0.500000 0.0 1.0 \n", + "3 fulltext multi_context 0.833333 0.0 1.0 \n", + "4 fulltext reasoning 1.000000 1.0 1.0 \n", + "5 fulltext simple 1.000000 1.0 1.0 \n", + "6 global search+vector+fulltext multi_context 0.800000 0.0 1.0 \n", + "7 global search+vector+fulltext reasoning 0.500000 0.0 1.0 \n", + "8 global search+vector+fulltext simple 0.666667 0.0 1.0 \n", + "9 graph+vector multi_context 0.833333 0.0 1.0 \n", + "10 graph+vector reasoning 1.000000 1.0 1.0 \n", + "11 graph+vector simple 1.000000 1.0 1.0 \n", + "12 graph+vector+fulltext multi_context 0.833333 0.0 1.0 \n", + "13 graph+vector+fulltext reasoning 1.000000 1.0 1.0 \n", + "14 graph+vector+fulltext simple 1.000000 1.0 1.0 \n", + "15 vector multi_context 0.833333 0.0 1.0 \n", + "16 vector reasoning 1.000000 1.0 1.0 \n", + "17 vector simple 0.750000 0.0 1.0 \n", + "\n", + " std \n", + "0 0.447214 \n", + "1 0.447214 \n", + "2 0.577350 \n", + "3 0.408248 \n", + "4 0.000000 \n", + "5 0.000000 \n", + "6 0.447214 \n", + "7 0.577350 \n", + "8 0.577350 \n", + "9 0.408248 \n", + "10 0.000000 \n", + "11 0.000000 \n", + "12 0.408248 \n", + "13 0.000000 \n", + "14 0.000000 \n", + "15 0.408248 \n", + "16 0.000000 \n", + "17 0.500000 " + ] + }, + "execution_count": 98, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "context_precision_df = eval_df.groupby(['mode', 'question_complexity']).agg({\n", + " 'context_precision': ['mean', 'min', 'max', 'std']\n", + "}).reset_index()\n", + "context_precision_df.columns = ['mode', 'question_complexity', 'mean', 'min', 'max', 'std']\n", + "context_precision_df" + ] + }, + { + "cell_type": "code", + "execution_count": 99, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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wQOtz/ycZ8+eSb9+/aRQoUJiYmKiHNOWLl2a6PK3b98WHx8fMTU1FXt7exk6dKjs378/0Tr+S3VEVFSUDBgwQDw8PMTCwkKyZcsmHh4eMm/ePI3PeffunbRq1Uqsra0FgLJdkvrNJudYkpL1/DnBwcHSsGFDyZkzp2TKlEns7Oykfv36sm3bNo3lnj59Kv7+/mJraysmJibi7u6uFbe6PFOmTNGYnlSdlVh9oK539u7dK8WLFxdTU1MpUqSI1nsT1rtqqXlcSux86nPHRBGRU6dOCQCpWbOmEP1XqURSaTQ/IiJKkdGjR2PMmDF49uxZsscYIiIiw9K4cWNcvnw52a1yKO1dvnwZlSpVgoODA44dO5biAeBJv5ycnFCsWDGlm196c/HiRXh6emLlypVo27atvsMh0guO8URERERE9BWePHmCnTt38mLSwLm7u2Pbtm24efMmGjVqpDEOIpGuLV68GObm5hpdPIn+azjGExERERFRCoSEhOD48eNYsmQJMmfOjK5du+o7JPqCypUraw1IT6RLf/zxB65evYpFixYhICAgVZ4+SJReMfFERERERJQChw8fhr+/P7777jusWLEiyadqEdF/V48ePfD06VP4+vpizJgx+g6HSK84xhMREREREREREekEx3giIiIiIiIiIiKdYOKJiIiIiIiIiIh0gmM8kYa4uDg8fvwYFhYWUKlU+g6HiIiIiIiIiAyQiODt27fIkycPjIySbtfExBNpePz4MRwcHPQdBhERERERERGlAw8ePEC+fPmSnM/EE2mwsLAA8GnHsbS01HM0RERERERERGSIwsPD4eDgoOQRksLEE2lQd6+ztLRk4omIiIiIiIiIPutLw/RwcHEiIiIiIiIiItIJJp6IiIiIiIiIiEgnmHgiIiIiIiIiIiKd4BhPRERERERERJRuxcbGIiYmRt9hZDiZM2eGsbHxN38OE09ERERERERElO6ICEJDQ/H69Wt9h5JhWVtbI1euXF8cQPxzmHgiIiIiIiIionRHnXTKmTMnsmbN+k3JEdIkIoiMjERYWBgAIHfu3F/9WUw8GagjR45gypQpOHv2LJ48eYItW7agUaNGn33PoUOH0LdvX/zzzz9wcHDA8OHD0b59+zSJl4iIiIiIiCitxMbGKkmnHDly6DucDClLliwAgLCwMOTMmfOru91xcHEDFRERAQ8P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FSqE3bt3K++5cuUK6tSpA3Nzc9jb26Nt27Z4/vy5Mn/Pnj2oWLEirK2tkSNHDtSrVw+3b99W5t+9excqlQqbN29G1apVkTVrVnh4eODkyZM6Ly8TT0REREREREREaWjFihWwtbXFqVOn0KNHD3Tr1g3NmjWDt7c3zp07h5o1a6Jt27aIjIzE69evUa1aNZQoUQJnzpzBnj178PTpUzRv3lz5vIiICPTt2xdnzpxBcHAwjIyM0LhxY8TFxWl877Bhw9C/f39cuHABzs7OaNmyJT5+/KjTsnKMJyIiIiIiIiKiNOTh4YHhw4cDAIYMGYKJEyfC1tYWnTt3BgCMHDkS8+fPx6VLl3DgwAGUKFECEyZMUN6/bNkyODg44MaNG3B2dkaTJk00Pn/ZsmWws7PD1atXUaxYMWV6//79UbfupzGpxowZg6JFi+LWrVsoUqSIzsrKFk9ERERERERERGmoePHiyv+NjY2RI0cOuLu7K9Ps7e0BAGFhYbh48SIOHjwIc3Nz5U+dKFJ3p7t58yZatmyJAgUKwNLSEk5OTgCA+/fvJ/m9uXPnVr5Dl9jiiYiIiIiIiIgoDWXOnFnjtUql0pimUqkAAHFxcXj37h3q16+PSZMmaX2OOnlUv359ODo6YvHixciTJw/i4uJQrFgxREdHJ/m98b9Dl5h4IiIiIiIiIiIyUCVLlsSmTZvg5OSETJm00zgvXrzA9evXsXjxYlSqVAkAcOzYsbQOM0nsakdEREREREREZKC6d++Oly9fomXLljh9+jRu376NvXv3wt/fH7GxsbCxsUGOHDmwaNEi3Lp1C3/++Sf69u2r77AVTDwRERERERERERmoPHny4Pjx44iNjUXNmjXh7u6O3r17w9raGkZGRjAyMsK6detw9uxZFCtWDH369MGUKVP0HbaCXe2IiIiIiIiIKMO4O7GuvkP4rEOHDmlNu3v3rtY0EVH+X7hwYWzevDnJz/Tx8cHVq1eTfL+Tk5PGawCwtrbWmqYLbPFEREREREREREQ6wcQTERERERERERHpBBNPRERERERERESkE0w8ERERERERERGRTjDxREREREREREREOsHEExERERERERER6QQTT0REREREREREpBNMPBERERERERERkU4w8URERERERERERDrBxBMRERERERERUTpy9+5dqFQqXLhwQd+hfFEmfQdARERERERERJRqRlul8fe9SbWPat++PV6/fo2tW7em2mfqG1s8ERERERERERGRTjDxRERERERERESUhjZu3Ah3d3dkyZIFOXLkgI+PDwYMGIAVK1Zg27ZtUKlUUKlUOHToEADg1KlTKFGiBMzMzFCqVCmcP39evwVIAXa1IyLSAafBO5O97N2JdXUYCRGRYWC9SIaC+yIZCu6L/11PnjxBy5YtMXnyZDRu3Bhv377F0aNH4efnh/v37yM8PBy//vorACB79ux49+4d6tWrhxo1amD16tUICQlBr1699FyK5GPiiYiIiIiIiIgojTx58gQfP37EDz/8AEdHRwCAu7s7ACBLliyIiopCrly5lOWXL1+OuLg4LF26FGZmZihatCgePnyIbt266SX+lGJXOyIiIiIiIiKiNOLh4YHq1avD3d0dzZo1w+LFi/Hq1askl7927RqKFy8OMzMzZVr58uXTItRUwcQTEREREREREVEaMTY2xv79+7F79264ublh9uzZcHFxQUhIiL5D0wkmngzc3Llz4eTkBDMzM5QtWxanTp367PIzZsyAi4sLsmTJAgcHB/Tp0wcfPnxIo2iJiIiIiIiI6EtUKhUqVKiAMWPG4Pz58zAxMcGWLVtgYmKC2NhYjWVdXV1x6dIljWv7v/76K61D/mpMPBmw9evXo2/fvhg1ahTOnTsHDw8P1KpVC2FhYYkuv3btWgwePBijRo3CtWvXsHTpUqxfvx5Dhw5N48iJiIiIiIiIKDF///03JkyYgDNnzuD+/fvYvHkznj17BldXVzg5OeHSpUu4fv06nj9/jpiYGLRq1QoqlQqdO3fG1atXsWvXLkydOlXfxUg2Jp4MWFBQEDp37gx/f3+4ublhwYIFyJo1K5YtW5bo8idOnECFChXQqlUrODk5oWbNmmjZsuUXW0kRERERERERUdqwtLTEkSNH4OvrC2dnZwwfPhzTpk1DnTp10LlzZ7i4uKBUqVKws7PD8ePHYW5ujj/++AOXL19GiRIlMGzYMEyaNEnfxUg2PtXOQEVHR+Ps2bMYMmSIMs3IyAg+Pj44efJkou/x9vbG6tWrcerUKZQpUwZ37tzBrl270LZt27QKm4iIiIiIiEi/Rr/RdwSf5erqij179iQ6z87ODvv27dOaXq5cOVy4cEFjmojoIrxUx8STgXr+/DliY2Nhb2+vMd3e3h7//vtvou9p1aoVnj9/jooVK0JE8PHjR/z000+f7WoXFRWFqKgo5XV4eHjqFICIiIiIiIiI/vOYeMpADh06hAkTJmDevHkoW7Ysbt26hV69euGXX37BiBEjEn1PYGAgxowZk8aR6o7T4J3JXvbuxLo6jCR1ZdRyEZHusf4gIiIiIn1i4slA2drawtjYGE+fPtWY/vTpU+TKlSvR94wYMQJt27ZFp06dAADu7u6IiIhAly5dMGzYMBgZaQ/pNWTIEPTt21d5HR4eDgcHh1QsCRERERERERH9V3FwcQNlYmICLy8vBAcHK9Pi4uIQHByM8uXLJ/qeyMhIreSSsbExgKT7fpqamsLS0lLjj4iIiIiIiIgoNbDFkwHr27cv2rVrh1KlSqFMmTKYMWMGIiIi4O/vDwDw8/ND3rx5ERgYCACoX78+goKCUKJECaWr3YgRI1C/fn0lAUVERERERESUUaSXAbbTq9RYv0w8GbAWLVrg2bNnGDlyJEJDQ+Hp6Yk9e/YoA47fv39fo4XT8OHDoVKpMHz4cDx69Ah2dnaoX78+xo8fr68iEBEREREREaW6zJkzA/jU8ydLlix6jibjioyMBPC/9f01mHgycAEBAQgICEh03qFDhzReZ8qUCaNGjcKoUaPSIDIiIiIiIiIi/TA2Noa1tTXCwsIAAFmzZoVKpdJzVBmHiCAyMhJhYWGwtrb+pl5UTDwRERERERERUbqjfvCWOvlEqc/a2jrJB5wlFxNPRERERERERJTuqFQq5M6dGzlz5kRMTIy+w8lwMmfOnCrjRTPxRERERERERETplrGxMR+oZcCMvrwIERERERERERFRyjHxREREREREREREOsHEExERERERERER6QQTT0REREREREREpBMcXJyIiIiIiIiI6AucBu9M9rJ3J9bVYSTpC1s8ERERERERERGRTjDxREREREREREREOsHEExERERERERER6QQTT0REREREREREpBNMPBERERERERERkU4w8URERERERERERDrBxBMREREREREREekEE09ERERERERERKQTTDwREREREREREZFOMPFEREREREREREQ6wcQTERERERERERHpBBNPRERERERERESkE0w8ERERERERERGRTjDxREREREREREREOsHEExERERERERER6QQTT0REREREREREpBNMPBERERERERERkU4w8URERERERERERDrBxBMREREREREREekEE09ERERERERERKQTTDwREREREREREZFOZNJ3AERERET0P06DdyZrubsT6+o4EiIiIqJvxxZPRERERERERESkE0w8ERERERERERGRTjDxREREREREREREOsHEExERERERERER6QQTT0REREREREREpBNMPBERERERERERkU4w8URERERERERERDrBxBMREREREREREekEE09ERERERERERKQTTDwREREREREREZFOMPFEREREREREREQ6wcQTERERERERERHpBBNPRERERERERESkE0w8Gbi5c+fCyckJZmZmKFu2LE6dOvXZ5V+/fo3u3bsjd+7cMDU1hbOzM3bt2pVG0RIRERERERER/U8mfQdASVu/fj369u2LBQsWoGzZspgxYwZq1aqF69evI2fOnFrLR0dHo0aNGsiZMyc2btyIvHnz4t69e7C2tk774ImIiIiIiIjoP4+JJwMWFBSEzp07w9/fHwCwYMEC7Ny5E8uWLcPgwYO1ll+2bBlevnyJEydOIHPmzAAAJyentAyZiIiIiIiIiEjBrnYGKjo6GmfPnoWPj48yzcjICD4+Pjh58mSi79m+fTvKly+P7t27w97eHsWKFcOECRMQGxub5PdERUUhPDxc44+IiIiIiIiIKDUw8ZSKHjx4gIcPHyqvT506hd69e2PRokUp/qznz58jNjYW9vb2GtPt7e0RGhqa6Hvu3LmDjRs3IjY2Frt27cKIESMwbdo0jBs3LsnvCQwMhJWVlfLn4OCQ4liJiIiIiIiIiBLDxFMqatWqFQ4ePAgACA0NRY0aNXDq1CkMGzYMY8eO1fn3x8XFIWfOnFi0aBG8vLzQokULDBs2DAsWLEjyPUOGDMGbN2+UvwcPHug8TiIiIiIiIiL6b2DiKRVduXIFZcqUAQD8/vvvKFasGE6cOIE1a9Zg+fLlKfosW1tbGBsb4+nTpxrTnz59ily5ciX6nty5c8PZ2RnGxsbKNFdXV4SGhiI6OjrR95iamsLS0lLjj4iIiIiIiIgoNTDxlIpiYmJgamoKADhw4AAaNGgAAChSpAiePHmSos8yMTGBl5cXgoODlWlxcXEIDg5G+fLlE31PhQoVcOvWLcTFxSnTbty4gdy5c8PExCSlxSEiIiIiIiIi+iZMPKWiokWLYsGCBTh69Cj279+P2rVrAwAeP36MHDlypPjz+vbti8WLF2PFihW4du0aunXrhoiICOUpd35+fhgyZIiyfLdu3fDy5Uv06tULN27cwM6dOzFhwgR07949dQpIRERERERERJQCmfQdQEYyadIkNG7cGFOmTEG7du3g4eEB4NPT5tRd8FKiRYsWePbsGUaOHInQ0FB4enpiz549yoDj9+/fh5HR/3KHDg4O2Lt3L/r06YPixYsjb9686NWrFwYNGpQ6BSQiIiIiIiIiSgEmnlJRlSpV8Pz5c4SHh8PGxkaZ3qVLF2TNmvWrPjMgIAABAQGJzjt06JDWtPLly+Ovv/76qu8iMmijrVKw7BvdxUFE6U9GrT8yarmIiIgoQ2FXu1QmIjh79iwWLlyIt2/fAvg0XtPXJp6IiIiIiIiIiNIrtnhKRffu3UPt2rVx//59REVFoUaNGrCwsMCkSZMQFRWFBQsW6DtEIiIiIiIiIqI0wxZPqahXr14oVaoUXr16hSxZsijTGzdurPF0OiIiIiIiIiKi/wK2eEpFR48exYkTJ2BiYqIx3cnJCY8ePdJTVERERERERERE+sEWT6koLi4OsbGxWtMfPnwICwsLPURERERERERERKQ/TDylopo1a2LGjBnKa5VKhXfv3mHUqFHw9fXVX2BERERERERERHrArnapaNq0aahVqxbc3Nzw4cMHtGrVCjdv3oStrS1+++03fYdHRERERERERJSmmHhKRfny5cPFixexbt06XLp0Ce/evUPHjh3RunVrjcHGiYiIiIiIiIj+C5h4SmWZMmVCmzZt9B0GEREREREREZHeMfGUilauXPnZ+X5+fmkUCRERERERERGR/jHxlIp69eql8TomJgaRkZEwMTFB1qxZmXgiIiIiIiIiov8UPtUuFb169Urj7927d7h+/ToqVqzIwcWJiIiIiIiI6D+HiScdK1y4MCZOnKjVGoqIiIiIiIiIKKNj4ikNZMqUCY8fP9Z3GEREREREREREaYpjPKWi7du3a7wWETx58gRz5sxBhQoV9BQVEREREREREZF+MPGUiho1aqTxWqVSwc7ODtWqVcO0adP0ExQRERERERERkZ4w8ZSK4uLi9B0CEREREREREZHB4BhPRERERERERESkE2zx9I369u2b7GWDgoJ0GAkRERERERERkWFh4ukbnT9/PlnLqVQqHUdCRERERERERGRYmHj6RgcPHtR3CETpmtPgncla7q6ZjgMhonQluXUHwPqDiIiI9GC0VTKXe6PbOAwAx3giIiIiIiIiIiKdYIunVHbmzBn8/vvvuH//PqKjozXmbd68WU9RERERERERERGlPbZ4SkXr1q2Dt7c3rl27hi1btiAmJgb//PMP/vzzT1hZJbOZHRERERERERFRBsHEUyqaMGECpk+fjj/++AMmJiaYOXMm/v33XzRv3hzfffedvsMjIiIiIiIiIkpTTDylotu3b6Nu3boAABMTE0REREClUqFPnz5YtGiRnqMjIiIiIiIiIkpbTDylIhsbG7x9+xYAkDdvXly5cgUA8Pr1a0RGRuozNCIiIiIiIiKiNMfEUypQJ5i+//577N+/HwDQrFkz9OrVC507d0bLli1RvXp1fYZIRERERERERJTm+FS7VFC8eHGULl0ajRo1QrNmzQAAw4YNQ+bMmXHixAk0adIEw4cP13OURERERERERERpi4mnVHD48GH8+uuvCAwMxPjx49GkSRN06tQJgwcP1ndoRERERERERER6w652qaBSpUpYtmwZnjx5gtmzZ+Pu3buoXLkynJ2dMWnSJISGhuo7RCIiIiIiIiKiNMfEUyrKli0b/P39cfjwYdy4cQPNmjXD3Llz8d1336FBgwb6Do+IiIiIiIiIKE0x8aQjhQoVwtChQzF8+HBYWFhg586d+g6JiIiIiIiIiChNcYwnHThy5AiWLVuGTZs2wcjICM2bN0fHjh31HRYRERERERERUZpi4imVPH78GMuXL8fy5ctx69YteHt7Y9asWWjevDmyZcum7/AoMaOtUrDsG93FkdoyarmISPdYfxARERFRKmPiKRXUqVMHBw4cgK2tLfz8/NChQwe4uLjoOywiIiIiIiIiIr1i4ikVZM6cGRs3bkS9evVgbGys73CIiIiIiIiIiAwCE0+pYPv27foOgYiIiIiIiIjI4PCpdkREREREREREpBNMPBERERERERERkU4w8URERERERERERDrBxBMREREREREREekEE09ERERERERERKQTTDwZuLlz58LJyQlmZmYoW7YsTp06laz3rVu3DiqVCo0aNdJtgERERERERERESWDiyYCtX78effv2xahRo3Du3Dl4eHigVq1aCAsL++z77t69i/79+6NSpUppFCkRERERERERkbZM+g6AkhYUFITOnTvD398fALBgwQLs3LkTy5Ytw+DBgxN9T2xsLFq3bo0xY8bg6NGjeP36dRpGTERfZbRVCpZ9o7s4iIgMBetFMhTcF8lQcF+kdIwtngxUdHQ0zp49Cx8fH2WakZERfHx8cPLkySTfN3bsWOTMmRMdO3ZM1vdERUUhPDxc44+IiIiIiIiIKDUw8WSgnj9/jtjYWNjb22tMt7e3R2hoaKLvOXbsGJYuXYrFixcn+3sCAwNhZWWl/Dk4OHxT3EREREREREREakw8ZRBv375F27ZtsXjxYtja2ib7fUOGDMGbN2+UvwcPHugwSiIiIiIiIiL6L+EYTwbK1tYWxsbGePr0qcb0p0+fIleuXFrL3759G3fv3kX9+vWVaXFxcQCATJky4fr16yhYsKDW+0xNTWFqaprK0RMRERERERERscWTwTIxMYGXlxeCg4OVaXFxcQgODkb58uW1li9SpAguX76MCxcuKH8NGjRA1apVceHCBXahIyIiIiIiIqI0xxZPBqxv375o164dSpUqhTJlymDGjBmIiIhQnnLn5+eHvHnzIjAwEGZmZihWrJjG+62trQFAazoRERERERERUVpg4smAtWjRAs+ePcPIkSMRGhoKT09P7NmzRxlw/P79+zAyYqM1IiIiIiIiIjJMTDwZuICAAAQEBCQ679ChQ5997/Lly1M/ICIiIiIiIiKiZGJzGSIiIiIiIiIi0gkmnoiIiIiIiIiISCeYeCIiIiIiIiIiIp1g4omIiIiIiIiIiHSCiSciIiIiIiIiItIJJp6IiIiIiIiIiEgnmHgiIiIiIiIiIiKdYOKJiIiIiIiIiIh0goknIiIiIiIiIiLSCSaeiIiIiIiIiIhIJ5h4IiIiIiIiIiIinWDiiYiIiIiIiIiIdIKJJyIiIiIiIiIi0gkmnoiIiIiIiIiISCeYeCIiIiIiIiIiIp1g4omIiIiIiIiIiHSCiSciIiIiIiIiItIJJp6IiIiIiIiIiEgnmHgiIiIiIiIiIiKdYOKJiIiIiIiIiIh0goknIiIiIiIiIiLSCSaeiIiIiIiIiIhIJ5h4IiIiIiIiIiIinWDiiYiIiIiIiIiIdIKJJyIiIiIiIiIi0gkmnoiIiIiIiIiISCeYeCIiIiIiIiIiIp1g4omIiIiIiIiIiHSCiSciIiIiIiIiItIJJp6IiIiIiIiIiEgnmHgiIiIiIiIiIiKdYOKJiIiIiIiIiIh0goknIiIiIiIiIiLSCSaeiIiIiIiIiIhIJ5h4IiIiIiIiIiIinWDiiYiIiIiIiIiIdIKJJyIiIiIiIiIi0gkmnoiIiIiIiIiISCeYeCIiIiIiIiIiIp1g4omIiIiIiIiIiHSCiSciIiIiIiIiItIJJp6IiIiIiIiIiEgnmHgycHPnzoWTkxPMzMxQtmxZnDp1KsllFy9ejEqVKsHGxgY2Njbw8fH57PJERERERERERLrExJMBW79+Pfr27YtRo0bh3Llz8PDwQK1atRAWFpbo8ocOHULLli1x8OBBnDx5Eg4ODqhZsyYePXqUxpETERERERERETHxZNCCgoLQuXNn+Pv7w83NDQsWLEDWrFmxbNmyRJdfs2YNfv75Z3h6eqJIkSJYsmQJ4uLiEBwcnMaRExEREREREREx8WSwoqOjcfbsWfj4+CjTjIyM4OPjg5MnTybrMyIjIxETE4Ps2bPrKkwiIiIiIiIioiRl0ncAlLjnz58jNjYW9vb2GtPt7e3x77//JuszBg0ahDx58mgkrxKKiopCVFSU8jo8PPzrAiYiIiIiIiIiSoAtnjKoiRMnYt26ddiyZQvMzMySXC4wMBBWVlbKn4ODQxpGSUREREREREQZGRNPBsrW1hbGxsZ4+vSpxvSnT58iV65cn33v1KlTMXHiROzbtw/Fixf/7LJDhgzBmzdvlL8HDx58c+xERERERERERAATTwbLxMQEXl5eGgODqwcKL1++fJLvmzx5Mn755Rfs2bMHpUqV+uL3mJqawtLSUuOPiIiIiIiIiCg1cIwnA9a3b1+0a9cOpUqVQpkyZTBjxgxERETA398fAODn54e8efMiMDAQADBp0iSMHDkSa9euhZOTE0JDQwEA5ubmMDc311s5iIiIiIiIiOi/iYknA9aiRQs8e/YMI0eORGhoKDw9PbFnzx5lwPH79+/DyOh/jdbmz5+P6OhoNG3aVONzRo0ahdGjR6dl6ERERERERERETDwZuoCAAAQEBCQ679ChQxqv7969q/uAiIiIiIiIiIiSiWM8ERERERERERGRTjDxREREREREREREOsHEExERERERERER6QQTT0REREREREREpBNMPBERERERERERkU4w8URERERERERERDrBxBMREREREREREekEE09ERERERERERKQTTDwREREREREREZFOMPFEREREREREREQ6wcQTERERERERERHpBBNPRERERERERESkE0w8ERERERERERGRTjDxREREREREREREOsHEExERERERERER6QQTT0REREREREREpBNMPBERERERERERkU4w8URERERERERERDrBxBMREREREREREekEE09ERERERERERKQTTDwREREREREREZFOMPFEREREREREREQ6wcQTERERERERERHpBBNPRERERERERESkE0w8ERERERERERGRTjDxREREREREREREOsHEExERERERERER6QQTT0REREREREREpBNMPBERERERERERkU4w8URERERERERERDrBxBMREREREREREekEE09ERERERERERKQTTDwREREREREREZFOMPFEREREREREREQ6wcQTERERERERERHpBBNPRERERERERESkE0w8ERERERERERGRTjDxREREREREREREOsHEExERERERERER6QQTT0REREREREREpBNMPBERERERERERkU4w8URERERERERERDrBxBMREREREREREekEE08Gbu7cuXBycoKZmRnKli2LU6dOfXb5DRs2oEiRIjAzM4O7uzt27dqVRpESEREREREREWli4smArV+/Hn379sWoUaNw7tw5eHh4oFatWggLC0t0+RMnTqBly5bo2LEjzp8/j0aNGqFRo0a4cuVKGkdORERERERERMTEk0ELCgpC586d4e/vDzc3NyxYsABZs2bFsmXLEl1+5syZqF27NgYMGABXV1f88ssvKFmyJObMmZPGkRMRERERERERMfFksKKjo3H27Fn4+Pgo04yMjODj44OTJ08m+p6TJ09qLA8AtWrVSnJ5IiIiIiIiIiJdyqTvAChxz58/R2xsLOzt7TWm29vb499//030PaGhoYkuHxoamuT3REVFISoqSnn95s0bAEB4ePjXhq5XcVGRyV42XCXJ/2A9r4+MWi4g+WXLqOUC0lfZUlQuA9gOKZHsfTGDlgvIwPtiOioXwHoRSF9lY72YccsFcF80FBm1bNwX09f2AnS0zdLZOohPvf1EPl9WJp7+4wIDAzFmzBit6Q4ODnqIJm1ZpWThiSlaWq9YLqSrcgEZt2xWM/QdgW5k1HIBGXhfTMnCLJdByKhly6j1R0YtF8B9MT3KqGXjvpj+JHsrpKPtlZS3b9/CyirpcjDxZKBsbW1hbGyMp0+fakx/+vQpcuXKleh7cuXKlaLlAWDIkCHo27ev8jouLg4vX75Ejhw5oFKpvqEEGUd4eDgcHBzw4MEDWFpa6jucVMNypT8ZtWwsV/qTUcvGcqU/GbVsLFf6k1HLxnKlPxm1bCyXYRIRvH37Fnny5Pnsckw8GSgTExN4eXkhODgYjRo1AvApKRQcHIyAgIBE31O+fHkEBwejd+/eyrT9+/ejfPnySX6PqakpTE1NNaZZW1t/a/gZkqWlZbqsDL6E5Up/MmrZWK70J6OWjeVKfzJq2Viu9Cejlo3lSn8yatlYLsPzuZZOakw8GbC+ffuiXbt2KFWqFMqUKYMZM2YgIiIC/v7+AAA/Pz/kzZsXgYGBAIBevXqhcuXKmDZtGurWrYt169bhzJkzWLRokT6LQURERERERET/UUw8GbAWLVrg2bNnGDlyJEJDQ+Hp6Yk9e/YoA4jfv38fRkb/ezCht7c31q5di+HDh2Po0KEoXLgwtm7dimLFiumrCERERERERET0H8bEk4ELCAhIsmvdoUOHtKY1a9YMzZo103FU/y2mpqYYNWqUVpfE9I7lSn8yatlYrvQno5aN5Up/MmrZWK70J6OWjeVKfzJq2Viu9E0lX3ruHRERERERERER0Vcw+vIiREREREREREREKcfEExERERERERER6QQTT0REREREREREpBNMPNF/UlxcnL5D0JmMXDZKfzLaMIIZrTwJsf4goq+R0etGIiL6Nkw80X+SkdGnXT8jXWRdunQJERERStkyikuXLmm8zkjbLKM6c+aM8n+VSpVhLkg+fPig7H8ZpUxqGzduxNu3bzNk+dRlych1R0baXkDGKw8ARERE6DsEnVKpVAAy1rYLDg7GuXPnNKZl5HokI8nI2ykj/cYSyojbLSNvr5TKWFeoRF8wYsQI1KlTB2vWrEFISEiGSdLMmzcPffv2hbu7OxYvXqxx4Z+erVq1Cj/88APat2+P+fPnQ0QyzDZr164dBgwYgJkzZ0JEMsyBaevWrahXrx78/PwwatQoREdHKxck6VlgYCA8PDzQpk0bbNq0CTExMfoOKdUcOHAAc+bMgbe3N/r164fDhw9niG0GAOPHj8e0adNw48YNjTKl99/bwoULMWfOHERGRuLjx49QqVQZ4oR97NixOH36NB4+fKjvUFLV2LFj4e/vj1WrVuHevXvK9PS+HwKf6sY2bdrgr7/+QmhoaIa52bBr1y7MnTsX1atXR0BAAFatWgXg043L9F6+tm3bYvbs2di8ebO+Q0lVU6ZMwZw5c/Do0aMMc66odvDgQZw9exZAxkrydujQARMmTMDWrVsBIMNst0GDBmHNmjW4cOFChjmfSg0ZY+sSJcPHjx/RokULuLu7Y/PmzShXrhwWL16MR48e6Tu0b9a5c2fs3r0b3bp1w9atW9GuXTvMmTNH32F9s7p16yI4OBjZs2fHmjVr4OrqiqNHj+L9+/f6Du2bNWrUCE5OTggKCoKPjw+mTp2K8PBwfYf1zerVq4dTp07B09MTe/bsgZubGzZs2IAXL17oO7RvMmTIEMybNw8eHh7w8/ODv78/fvvtN32HlSqqVq2KQ4cOYdCgQfj48SOqVauGkSNH4sGDB/oO7Zu9efMG169fR/ny5dG7d2/l5DY9Xxzfvn0bz549w6xZs9CkSRN06dIFz58/T/cn7Pfu3cP9+/fRvXt3tGvXDhMmTMCHDx/0HVaq8PDwgI+PD3755Rf8/PPPGDJkCACk+wuSd+/eoUSJEoiNjcXo0aNRs2ZN7NmzBx8/ftR3aN/M19cXmzdvxt69exEZGYlp06ahUaNGGeJmSrly5XDv3j307NkTjRo1wtatWxEdHa3vsL5JTEwM7t+/j5MnT6JkyZIYNGgQ9u3bp++wUsXBgwcxevRoNG/eHC1btsTmzZsRExMDlUqF2NhYfYf3TWrVqoXbt29j3Lhx8Pb2xp9//onXr1/rO6xv9u7dOxw/fhze3t4YPHgwdu/ere+QDIMQ/QeFhYXJtGnTJHv27NKhQwc5fvy4vkP6arGxsRqvr127JpMnTxZjY2MZMGCAxMXF6Smyb/fx40cREYmKipLHjx9L06ZNxc7OTubPny8vX77Uc3RfL/42CQ8Plz59+sj3338vNWvWlBcvXugxsm+n3mZxcXESExMj7dq1ExcXFxk9erQ8fvxYz9F9nYS/oVOnTknz5s2lXLly8ssvv+gpqtTx8eNHZZuJiERHR8u6devEwsJC2rdvL5cvX9ZjdF8vYb24adMmad++vTg5Ocm4ceOU6em5fnz//r0sW7ZMqlevLjlz5pQ9e/ZIdHS0vsP6ZleuXJGVK1eKpaWl+Pr6yo4dO/Qd0ldLuH/duHFDZs2aJfny5ZMaNWqk+/o+vgsXLki/fv3EyMhIhgwZInfu3NF3SF8tKipK4/Xz589l//79UqBAASlTpow8evRIRNJ3/REXFychISFSt25dqVixonTv3l0iIiL0HdZXSVjfr1y5Ulq1aiVOTk4ya9YsPUWVuj58+CB37tyRxo0bS+XKlaVOnTrK9kpY/vTm/fv38uTJE6lbt66UKFFCBgwYIA8fPtR3WF8lYZ2wbds2qVevnpQpU0bGjh2rp6gMBxNP9J+Q1MnBzp07pWTJktK8eXM5ffp0Gkf17T530vP777+LiYmJDB8+PA0jSn0Jy9irVy/Jly+fLFu2LF2f9ImIvHnzRkREYmJiZPPmzVKxYkUpWbJkurwYSXjiE/8CeOTIkeLh4SGBgYHy7t27tA4tVcTFxUlcXJxSzpCQEBk6dKi4u7vL5MmT9Rzd1wkPD1f+v3//fo15wcHBki9fPunYsaO8ffs2rUP7Zuq6If5+ef/+fZkxY4ZkypRJBg0apK/QUkX8BG94eLh06NBBsmbNKqtXr06X9WJsbKxW3Hfv3pVKlSpJ5cqVZeXKlXqK7NuoyxS/bNHR0XL27FkpXLiweHt7y/v377WWSU8S1v2rVq0SW1tb6d69uzx48EBPUX29Dx8+KP/ftm2bvHr1Snl9584dKVasmHh7eyvT0tN2i7+t1HFHRkbK5MmTpVy5ctKiRQuJjIzUV3jfLP62uHPnjowfP15UKpVMmDBBj1F9vbi4OK0k6Nu3b2Xr1q1SqlQpKVSokDx//lxE0l/yKal4x40bJ97e3tKhQ4d0f7NS/e+tW7dk/Pjxki9fPunXr58+Q9M7Jp4owztx4oScO3dORES6dOki06dP15gfHBws7u7u0qdPH4mOjk43JxHx4/z999/l2LFjWsusXr1azMzM5LfffkvL0L5Jcg6eP//8s9ja2srdu3dFJP2c+P3555/KifjIkSNl6dKlSoImLi5ODh48KJUqVZJWrVqlqzuP8df/ypUrNVqqqQ0ePFjy58+vJHjTw0nSl2J8/Pix9O/fX6pVqyZHjhxJo6hSx8aNG+WHH36Q9+/fS+/evSVHjhzy9OlTJcEm8ml/NTY2lvnz54tI+vmdxY8zNDRUY9779+/l119/FTMzM5k5c2Zah/ZNElv/8ffRXr16ibm5uZw5c0ZrniGLn5xYsGCBxrwnT55Iw4YNpWrVqnLy5Mm0Di3VXLhwQWvanTt3xMnJSZo0aaKHiL5NYvtW/JaTGzduFHNzc5kyZUqSyxui3bt3S5EiRUREpE+fPuLi4qJ18fvvv/9K/vz5pVu3bvoIMVUkvLkVFRUlixcvFm9vbxk5cqTExMToKbKU+9y+9e7dO5kzZ46YmJjIsmXL0jCq1BH/Rt2ePXs0WtpduXJFypUrJ25ubkqyNL0co+NT39iKvx1nz54t5cuXl0mTJmkl3gxZwvUf//WLFy9k7ty5kj9//nR37pGamHiiDCsuLk6ePn0quXPnllatWomfn59ky5Yt0RPADRs2iLGxsezZs0cPkaZc/Ar677//lrJly0qNGjXk4sWLGsu9e/dO+vXrJ3Xr1tW6ADNE8cu1ZMkSGTZsmPz4449y9OhRefbsmcay1apVk+rVq6d1iF/twYMHUrFiRalUqZJ07txZjI2NlW5M8VtnLF26VCpVqiR//PGHxjxDFX+bPXjwQDJnziwNGjRINPlUu3ZtKVOmTJrH+DXil2vNmjUyePBgGT58uGzYsEFjuevXr0vZsmWlb9++ImL420vt7NmzolKppGjRomJlZSWXLl0SEe2WQjNmzJDcuXPLlStX9BZrSsTfbqtXr5amTZtq1fnv3r2TsWPHSvny5eXvv/9O6xC/Svxy3bt3T27fvp3oCXnTpk3F2dlZozWbIfvzzz/Fw8NDDh48KL169RKVSiW3b98Wkf+V+fHjx1KsWDH58ccf9RlqisTfXvv27ZPixYvLmjVrtObv379fnJ2dtRJuhix+2U6dOiXBwcFy+fJlrZYyc+fOlcyZMyuJ0PTgypUr4ubmJg4ODmJlZSU3btzQWkZ9nK5SpUqi55OGKP42mzFjhlSsWFGrTv/w4YMMHjxYvv/+e/n3339FxPCPZ/HLdfXqVbl+/bpcu3ZNY5k3b97I4MGDpWLFiulme4l8uinu6OgocXFx0q9fP3FxcZGnT59qLHPu3DkpU6aM/PzzzxqJX0MWf5stXrxYPDw85P79+yKiub/169dPXF1d00231oT7ovovvrCwMBkwYID4+vrKP//8k9YhGgQmnijDu3jxotja2krmzJll3bp1yvSElVj//v2lUqVKBj92UPy4f/nlF2nbtq24urpK5syZpXbt2lpdBg8ePChFihSRv/76K61D/WoDBgyQXLlySa9evaRJkyaSK1cuGTFihLx//16p3I8ePSrVqlVTWrOlB3v37pVcuXKJqampkuRU31lUb9fo6GipW7euNG7cWG9xJlf8fXHMmDHSunVrcXZ2FpVKJTVq1NBKPt26dUsqVKggu3fv1ku8X2PAgAGSO3du6dChg/j5+Ym1tbWMGTNGRP5X/j179oi5ubmcPXtWn6EmS1xcnLJdWrduLSqVSmrXrp1kvffgwQNp3Lix0mrSkE/+4p/4nTx5Un788UextbUVPz8/rbGqLly4IFWrVpWFCxeKiGGXK35so0aNkuLFi0v+/PmlUKFCsmTJEo2k/LVr16R69erpppVaRESEVK5cWfLmzSuWlpbKb0i9LdX/Xrp0SczNzWX16tV6izW54u+HGzZskM6dO4uNjY0ULVpUq/Xxq1evpFevXtK5c2cRMfztFT++IUOGSP78+cXd3V1y584t/v7+WnWgv7+/tG3bVt6/f2/QZYu/zX766SdRqVRKy6eE80U+ddv19PSUqVOnplmMXyt+7MeOHZOpU6eKSqWS5s2bKwkmtbdv34qrq6v89NNPaR1misXfn0aMGCEeHh7i7Ows+fLlk8DAQI3u/n///bdUrlxZqT/SQwu8kydPSuXKlSVXrlxiY2OjJGfii4mJkZkzZ0r16tUlJCRERAy7Dom/3nfu3CkzZswQlUol9evXV8Z0ih+/l5eXtGzZMs3jTKn4MQ8bNkxKlCghDg4O4uXlpdyUVDt//ry4uLgo5x7/NUw8UYYUv3K7du2aFCxYUPLmzSt+fn4aiZn440ocO3ZMqlSpIk+ePEnzeL/G9OnTxcLCQoKDg+XOnTuyYMECKV++vPj6+mqd/HXp0kVat25t0AcktR07doijo6NyZ+rYsWOiUqnk999/11guIiJCKlasKKNHj9ZHmMmW8O6wh4eHeHl5aZwoqBMB8ccPcnZ2lhMnTqR5vF9j0qRJYmVlJQcPHpTTp0/LihUrJG/evFK1alWNsWgiIyOlUaNGBj3uWPy7hrt27RJHR0eli4+662piTfbbtGkjy5cvFxHDPvFTi4yMlN9//13Wrl0rWbNmlebNm8u9e/cSXbZPnz5Svnz5NI7w66m7yHTv3l1++OEHyZYtm/j5+Wnd7Z45c6bkzZtXqzWloRo3bpzkzJlTduzYITExMVK1alVxdHTUuKsaHR0tPXr0MPjuW7GxscpvLTAwUExMTKRYsWKyb98+JVGdsPXd8OHDZcCAARrzDNnAgQMld+7cEhQUJBMmTJCiRYtK2bJlZcWKFRrLnT59WqysrAy+K2H8dT5r1izJlSuXHD16VEQ+tU4wNzfX6nL822+/SYUKFdLNoPcPHjyQv/76S7Zs2SKenp7i4eGhtB6M3y1e5NPxoEqVKgZ/s1Jt4MCBkidPHhk3bpz4+/uLlZWV1KxZU65fv66x3NGjR6V8+fLKUAaGbvz48ZIjRw45fPiwPH/+XLp06SIqlUquXLmidaO2QIECBt8aNGH3aZVKJfnz51e6pMU/pxL51KKrSJEiMnjw4LQP9isNGjRI8uXLJxMmTJD27dtLrly5pGLFikrrJnUZDx06JHXr1jXY31jCBOb48eMle/bscuTIEXn8+LEEBASISqWS8+fPa+yLCxcuFFdX13TREyW1MfFEGVr8p5+dPn1a8ufPLz/++KNG0+/4lYGPj4/MnTs3zeNMCXWLhUaNGsnPP/+sMW/9+vXi7OwstWvX1rjI2r17t0ycONHg7vL8+uuvWic9a9askdq1ayv/t7CwkHnz5onIpy4yV65cUU4Ad+/eLcOHD1cGZzVkv//+u9y6dUtevXolu3btkqpVq0qVKlW0Tu5ev34tkZGR0qRJEzlw4ICeok2+6Ohoad68uXJBKPLppOHQoUNiZ2cndevW1UjmHD58WHr27Glwg4xPnz5daX2m/nfu3LlSs2ZNEfn0VDQLCwulS8zbt281EoPjxo1LN4NGzp49W9q2bau8PnXqlGTJkkWaN2+uMd6OunVGWFiYjBs3TmOQXUN18OBBsbOz02jhuWzZMilWrJi0adNGo3vJixcvpGnTpgbZjTD+gO6xsbHy5s0bqVq1qqxatUpEPt0ttrKyUlo2xf+N3bt3T4oWLZouWuDdvn1brl27JufPnxcfHx8pU6aMbN26NdExZtauXSt58uRJF4nCa9euSYECBTSeyHfu3Dlp1qyZlChRQtavX6+xfM+ePWXz5s1pHWayxO+6FL+1pPrpkJs2bdLYFz98+KA8OENExNvbO12MMzljxgyN7pwXL14Ud3d38fDw0OhGuGzZMnnz5o38888/MnbsWIM7liXm9OnTkiNHDgkODlamXb58WXLkyCG1atXS2MY3b96U0qVLG3RrcvV5+4cPH6Rhw4bK/rVlyxaxsbFR9sX4Cc+wsDD54YcftFp5Gap79+7Jn3/+KevWrRMfHx9xcXFRboyrk/Pqc/qtW7dK06ZNNX53hur8+fNiZ2enMbTJpUuXpECBAlKpUiWNp9ndvXtXChQoIAcPHtRDpMmjPlapb6yq6/bt27eLtbW10rIp/kMLrl+/LnXr1k3yZl9GxsQTZVg3btyQnDlzalxUHDlyRPLnzy9t2rRRLkyqVKmiHKT++ecfg7wISUy7du2kadOmWifoAwcOFFNTU2nQoIFy4hAdHS2nTp3SR5hJCg4OFiMjI+nXr58ypoeISFBQkFStWlWOHj0qlpaWGonAVatWSe/evZUL4LCwMGVsGkN27949UalUcvjwYWXali1blHGq1Mmndu3aydq1a0Xk0wX0vn379BJvSlWuXFnq1aunMS0uLk4GDBggKpVKfH19lelv3rwxuBO/ffv2iYODg7Ru3Vrj97R69Wrp0KGDbNiwQczNzTXGYdm+fbv0799fORGMjY1NN2OZ/PTTT1K1alUR+d+J6+nTpyVbtmzSpEkT2b59u9SvX1+KFCmiPFUn4bgZhurw4cOSK1cura51ixYtEiMjI62WTzNmzJDz58+ncZSf17hxYwkICNAYADg0NFQKFSokT58+leDgYDE3N1eOWxERETJjxgwlaRgZGSmLFy82+MdR//7771KkSBHlIkqdXCtTpowyxp3IpwcxqM2ZMyddtMR4+PCh5MqVSyvhcvHiRbGzs5OiRYsqSUSRT911DXG8sR49eoi3t7ccP35cmfbhwwepWrWqHDhwQE6ePKlRN0ZHR8uMGTNk//79St1y8ODBRMdKMjSBgYHi6empMe3y5ctSvHhxcXNzk3379kn16tU1nmiXHsolIvLXX39Jnjx55ObNmyLyv4TMqVOnxNTUVFq1aqVxXN6yZYvSms1Q+Pn5iY+Pj/I6NjZWXrx4IXZ2dnL48GH5888/NerFqKgoGT58uHJc/vjxo0yePFnr2GCIpk6dKi1atFBenzhxQipXriwuLi4SFhamTF+zZo08f/5cLly4IH379jX41lwiIsePH9d4OJC6njh58qRkzZpVGjVqpLR8EhE5cOCAwd1ECQgIkJIlSyqvY2NjJTw8XJycnGTv3r2yd+9ejX0xOjpaJk6cqJFACwoKSldDoKQWJp4ow0jYmicyMlJy586tZJvjjw1UpEgRKVOmjLi7u0vhwoWVE19DbA6eVCulwMBAsbOz0zo5WLhwodSuXVtq1aol/fr1M+gnQixbtkwcHBykb9++cuvWLRH59BSjggULikqlkqVLlyrLvn//XurWrSsdOnQw+G4WCeN7/vy55M+fX/bu3asxfevWrVK9enXJnTu3VKpUSfLly2fQ2yupfXH58uXi7u6uMYaayKeLfT8/PylQoID4+/unRYhfJSIiQhYtWiSlSpWSVq1aKcmn4OBgyZYtm6hUKqXVnXr5WrVqSdeuXQ1+X0xsm23YsEHKlCkjkZGREhcXp9R7Z8+elUKFCknJkiXF29vbIOvD+BJ7VP3hw4fF1tZWaS2oLkNMTIwULlxYihUrJj169NA4sTU08+bNE5VKJcOHD9dIPtWqVUuqVq0q5ubmGnXj/fv3pWLFihqtaNJDq6Bff/1VcuXKpVHnhYeHS7Vq1aR06dIyfPhw8fX1FSsrK2U7GuLjtRP7jT148EA8PT1l2LBhEhUVpbGP1q9fX7y9vaVWrVoaNyMM0blz58TNzU0aNGig8eTcXr16iZ2dnZiZmWkk0F68eCFVq1aVoKAgZZohtkhOql50cnLSmnfz5k35/vvvxdXVVapVq5Zu6sX47t27J2ZmZhpj2sXFxcnz58/Fzc1NMmfOLI0bN9Zq9WtI/vjjD7Gzs5PmzZtrTA8ICJBGjRpJ1qxZZcmSJcr0R48eSa1atWT58uXKNjX047XarFmzpGzZshrxnjx5UqpUqaIkN3x8fMTb21spmyEm5BNb369evZIcOXLIxIkTNaY/ffpUihUrJlmyZFFujImIwbUo/Pjxo2zYsEGKFCkitWrVUqZHR0dLp06dpHnz5mJpaakxhtO9e/ekXr16smrVKoPreZLWmHiiDCcyMlJpDl6jRg2ZPHmyiGg+XevcuXMyffp0GTdunHKANcSTifgV1LZt22Tz5s2ya9cuZVrt2rUlT548snv3bnnw4IFERERIw4YNZfHixTJhwgSxtrbWegqGIYhfrqVLl0revHk1kk9LliyRQoUKSdu2beXatWuye/duqV27tri7uyvbKz1U3vH7pTdo0ECGDRsmIpqx//XXXzJhwgQZOHCgQZ/0xY85ODhYNm7cqLRUu3fvnjRu3Fhq166tjF/y/PlzadCggUycOFFmzpwpRYoUkTt37ugl9s9Rnxi9f/9eFi1aJF5eXvLjjz8q9cHChQtFpVLJhAkT5MCBA3L8+HGpUaOGeHh4aA0Mb8iWLl0qe/bskfPnz8uGDRvEzs5Oq5uryKeWNdevX1e2tyHuiyKa++Pbt281tkHTpk0ld+7cGuV78uSJ+Pn5yS+//CLW1tYaXU4M0YoVK0SlUsmwYcOUOnzlypVSoEABjZPdd+/eia+vr8Z4aoYosd/IgwcPxMXFRWlNp05QvH37Vtq2bSu1a9eW+vXrG+SxWS3h0wafPXumTJs7d64YGRnJvHnzJCIiQkQ+Ja1btGghCxcuFBcXF+VBBYZIvT9duXJFXF1dpX79+kqi7ObNm1KjRg0pVKiQvHr1SmJjYyUsLExq164t5cqVM+h9Mb4VK1bI7Nmz5fz587J3714pVqxYkl3Mrl69mq7qxbCwMI2HSQwbNkwcHBw0bhC9e/dOunfvLsHBwWJmZiazZ89O85iTKy4uTg4cOCA5cuSQpk2bKtMXLFggOXPmlEaNGimJ+hcvXoivr69UqlRJa0wkQ5NUEtTW1lYraXvu3DmpX7++ODk5iY+Pj9a4Ywn/r0/xy/XixQuNrmbDhg2TkiVLaiQK3717J+3bt5c///xTsmfPrpWYMiRRUVGyY8cOcXFxUYZjEPl0E1b9ZGf1zZ9nz55p7Yv/ZUw8UYYyf/58sba2lvLly0uvXr2kaNGiyiDOnxufxBArg/gHj759+0r27NnFyclJ8ubNK927d1fmNWzYUPLmzSsODg7i4uIihQoVEpFPg3I7Ozsb3B1idbnir/PFixdLnjx5pE+fPvLo0SOJjIyUFStWiIuLi9jY2EiJEiWkYcOGykHWELdXQhMmTJBixYpJ2bJlpWvXruLq6ir+/v7y/Pnzz94BNvSyDRw4UCwsLMTR0VEyZcoks2bNEhGRf//9V1q1aiXfffed5M2bV5ydncXNzU1EPnVLK1CggMHui+oTpMjISFmwYIGULFlSWrRooexvU6ZMkfz584uNjY2ULVtW6tSpk672xXPnzkmpUqXE0dFRsmXLJt7e3qJSqaRWrVoye/Zs+f333+X58+caXV5F0kdyNzAwUCpUqCCNGzeW6dOni8inBEaNGjXExsZGpk6dKosWLRIfHx+lm4arq6v07t1bj1EnLX69v3z5clGpVDJ06FCJjIyUd+/eyZAhQ8TZ2VlKly4tP/74o5QvX16KFy+ebvbHwMBAGTVqlCxcuFC2bt0qNjY2sm3bNq3lYmJi5M2bN8r6MNQLfbURI0ZIgQIFxN3dXZo0aaLc6Bo3bpwYGxtLixYt5KeffpKKFSsq3blat24ttWvXNujfmXp/unz5shQpUkTq1aunDIK+fft2KVeunFhZWUnJkiXFy8tLSpcunS72xbi4OPnnn3+kQoUK4uDgIIULFxY7OztRqVTSoEED6d27t+zYsUP++ecfrUSUIW8vtbFjx4q3t7eULl1aFi1aJC9fvpSnT59Kt27dxMbGRvr37y8zZ86UatWqiZeXl8TGxkrlypU1zi0NUVxcnOzfv19y5Mih8QCFUaNGSeHChaVkyZJK8rNEiRLpYl9UW716tQQFBcmVK1dk69at4u3tnejNIRFJFzeH1MaMGSOVK1eWokWLysqVK+X169fy8OFD6dKlixQuXFg6deokc+fOlcqVK0u5cuXk3bt3UqlSJenVq5e+Q/+sqKgo+eOPP8TFxUWjC2hQUJBYWVnJ999/L1WqVJEKFSqIp6dnutoXdYmJJ0rX4ne1iI2NlVOnTsnSpUtl+vTp8uOPP0qFChVEpVJJ7ty5pVixYuLj4yMNGjQw6D7eCe9WPHr0SMqVKyeXLl2Sf//9V3799VfJmjWrdOzYUVlm+/btsmLFCvn111+VSq1bt25SpkwZgxpsMP4JW/y7HyKf7lrlyZNHevfurdEN5sKFCxIaGmrwFyAJt9vhw4dly5YtEhAQID///LPkzZtXVCqVVKtWTfLlyyeNGzeWtm3bGuS4HvHFP0iePHlSSpUqJceOHZPXr1/L2LFjxcLCQiZMmCCxsbHy6tUruXjxokycOFHWrFmjbKsePXpItWrV5PXr1/oqhpaEFw/qkwL1+DglSpTQaPl0584duXbtmty7d8/g98WkLoxevHghd+/elR07dkju3LnFx8dHihUrJrlz5xY7Oztp1KhRGkeacvHLNnPmTMmePbuMHj1aGjduLK6urtKjRw9lfo8ePcTLy0vc3NzE19dXSfiWKVNGo+ukIUhqmy1dulRUKpUMHjxYYmJi5N27d3LgwAHx9/eXgIAAmTRpkkG3lIzvyZMn0qVLF6levbo4Ojoqx2dra2vp1KmT9OvXTw4cOKAxvpOI4dzBjy/+9tqwYYPkzJlT1q5dKxMmTJASJUqIm5ubknz67bffpEOHDlKjRg3p2LGjcuyrW7eu1qO2DUFS++KFCxekSJEi4uvrqzwd+OXLl7JgwQKZOXOmrF+/XjleGOK+mFS5oqOjJTQ0VHbu3Ck5cuSQevXqKa1aM2fOLC1btjTIfTC++GVbtGiRZM+eXebNmycNGzaUkiVLSo8ePeTFixcSHh4uc+fOlcKFC0v58uU1WhRWqVJFxo4dKyKG85tLbJvFxMTI/v37JXv27NK4cWNl+rZt22TSpEnSu3dvWbBgQbqpF+Pi4uTOnTtSunRpKVSokBQpUkRsbGyUJGjPnj1l586d8tdff2lduxhiEjR+TPPnz5ccOXLIjBkzpEWLFpIvXz4ZOHCgvHjxQsLCwpSnu5UvX17q1aun1Jk1atRQWoMa8r4YGRkpf/zxhxQuXFiqV6+uTP/jjz9k2rRp0rt3b1myZEm62RfTAhNPlG7FrwQSa0Hy8eNH2bZtm1SpUkX2798vO3fulF69ekm3bt0M9sefMEk0bdo0qVevnnTo0EE5OXj//r3yCPT4ySe1CxcuSOfOnSV79uxy8eLFNIk7OeIfPKZNmyYNGjSQH3/8UTnREflf8qlv376JDtppiAdZEe24Etsft2zZIg4ODrJp0yaZPXu2DB06VBo1amSwdz8SDgAeFBQk/fv312opMn78eLGwsJCJEyfK8+fPNeZdvHhR+vTpI5aWlga1L8Y3ffp0adWqldSvX1+WL18uUVFREhMTI0uWLNFKPsWXHvbFv/76S/bu3avVrezjx49Srlw5mTp1qoh8auL+119/Gey+qJbw6YgTJ05Uuh6/fPlSZs+eLfnz59e4ax8aGqrxhLjhw4dL3rx5lW69hiD+Njt37pwcPXpUHjx4oOx3ixcvVpJP8csSnyFuuy/9Ru7duycNGjSQmjVrSps2baRSpUpSuHBhqVChgsFcbCQmfmzr1q2TpUuXyvLly5V5p06dkmLFiomrq6tyIRX/mPDy5UsZOnSo2NraytWrV9M2+C+Iv8127NghS5YsUbryi3x6IpU6+RT/qZ7xGfq+eOLECdmwYYOcOnVK66lSLVu2lM6dO4vIp4vKf/75xyDLk5S///5bevToIVu2bFGmTZo0ScqUKSMBAQHKwzDevn2rsU4GDhyoMfi4IUh4LNu3b588ePBASdzu27dPbGxsNJJPCRnqtksqoSYiEhISIgcPHhQrKyspV66cNGvWTNzc3CRTpkzStm1bg64b47t06ZL06NFDtm/frkybNm2aODs7y4ABA5QbzB8/ftQ4xxowYIDkzp3bYPfFY8eOyZ9//qlRd+/cuVMKFSqkkXxKyFD3xbTGxBOlSwnvejdo0EB8fHykU6dOGhXY5cuXxcTEJNGnTRlaJdChQwdp2LChiHw6eY2IiJBx48aJra2txlNURP6XfLKwsJBmzZppTN+5c6fUqFHDoC704x8oAwMDxdzcXPr16yeNGzdWuo2oLVq0SL777jvp2LGjQQ8ArBZ/XwwKCpK2bduKu7u7zJs3T2miHxsbK8eOHZP8+fMnOuivoSUxmjZtKgMHDtSY5ufnJyqVSqpUqaL15JQJEyZI9uzZZfjw4RpdWufNmye+vr4GtS/GX9fDhg0Ta2tr8ff3l5YtW4qxsbF07NhRuehftGiRlClTRmrVqmVw9cWXDBo0SNzc3KRAgQJStmxZqVChgkbdOHDgQPHz89N6nyGWs23bthr73OHDhyVv3rySM2dOpduPyP+STwULFtTqMvLvv/9Kx44dxd7e3mAfE96vXz9xcHCQrFmzKklP9dhA6uTT8OHDDXLcvoQSjk84d+5cmTZtmlbsXbp00egy8/Tp00QHjTcE33//vUay5caNG0pL1sWLFyvT1cmn4sWLi7u7u8b4ko8fP5YePXqIo6OjwT1NMWH3/hw5coiTk5O4uLhIgQIFlFZO58+fF1dXV2nYsKEyiH96MXDgQClYsKC4urqKt7e3VKhQQaM+6NWrl9SpU0frfYZYL/bs2VPjqVh79uyRwoULS+7cuWX37t0ay06ePFnKli0rAQEBEhISokw/d+6c9OnTR/LkyWOw9eLAgQPFxsZGcuXKJZaWltK5c2flKWf79u2THDlyaA04bsji141Hjx6VTZs2yYkTJ7SeQtq5c2fp0qWLiIi8fv1a7t69a5D7ocinbRS/blQ/1c3Ozk4jCSry6TzZxcVFBg0apHGD8+zZsxIQECAODg4Guy8OGDBArK2txcHBQYyNjaVr167KU3J37twpLi4uGmMwkjYmnihdGzx4sNjb28vUqVNl/fr1YmxsLPXr15d3797Jx48f5dWrV1KoUCHZv3+/vkP9opCQEI1WTSKfTlKnT58umTJl0niktMinrmpLliyRatWqaSUuDO0pEGqnT5+Wli1byp49e0Tk0wH4+PHj4urqKpUrV1aWmzVrljRs2NDgLjw+R70vTpo0SYKCgsTa2lpat26tJJqio6PF0dFRqxuJITp//rxysRQ/+Tdo0CBRqVSybNkyiYyM1HjPkCFDpGbNmlrbzJC618V3+/ZtGThwoMZTIXfv3i12dnYSEBAgIp9+R0FBQdKhQweDSw5+zvTp0yVHjhzKRcnEiRNFpVJpXCTOmjVLChYsaNADN4t8asHZpk0bjThv3LghQ4YMEWtraxk8eLDG8q9evZK5c+dKtmzZZNq0acr0Fy9eyM6dOw22pdPmzZulcOHCcuDAAbl06ZLMmjVLSpcuLVWqVFGST+oxn+I/LcfQDRgwQAoUKCBVqlSRGjVqiImJiRw9elSpJ7Zu3SpeXl7y/v17jbrD0H5v4eHh8ssvv2h0EY+IiJAtW7ZIsWLFtG4OxcXFyZkzZ8Te3l7atGmjMf3mzZtKCyJDEX/dHz16VMqVKyd///23vHnzRv7++29p1qyZmJubK8myS5cuSfbs2bVuUBiy+fPni729vfJ0vuHDh4uZmZns2LFDWUZ98WjoT4U8ffq0BAQEaLXe79+/v9ja2kqXLl20xjWdOnWqFChQQKNeDA8Pl507dxrUE9Hi74sHDhyQ/PnzS3BwsISFhcmyZcukcuXK8sMPPyjdzg4cOKAk5dOTQYMGiaOjo5QsWVJpRRj/KZc9evSQSpUqiYhmfWhoyafLly9L+/bttfbF4cOHS5YsWaRPnz4SFhamMW/GjBlibW0tc+fOVaZ9/PhRtm/fbrD74qlTp+S7776Tw4cPy6NHj2TTpk3i7u4uLVu2VMbc2rFjh1hbWxvsGJKGgIknSreuXLkibm5u8ueff4qIyK5du8Tc3FwWLFigsZybm5uMHj1aHyF+lSVLloidnZ3SbSksLEymTJkiVlZWWk/AiX8xZmgn6gn99ttvUqpUKSlUqJD8888/yvSPHz/Knj17pEiRIhongAkHfjZkf/31lxQuXFgZr+n06dNiZGSkPGY6NjZWPn78KPb29gZ/0Rj/QDt79mypU6eOxp2sbt26iZmZmaxcuVKrS2H8lgqGnDTcvHmzqFQqyZMnj5w6dUpE/refbd26VYyMjJSEVPxHoRvqvhh/XcfExEiHDh1k/vz5IvKpPJaWlrJo0SIREaWr1u+//y7169c36O0korkvLVy4UKkX7927J8OGDZNChQrJ+PHjNd7z4sUL2bRpk8GdoCdl27Zt0rt3bxk6dKgyLTo6Wnbs2CElS5aUYcOGKfverl27DLareEIrV64Ue3t7pcXxpk2bRKVSyebNm5Vl/vrrLzExMTHIJ14mZcKECcqA6O/fv5c//vhDChQooPF0I5FP++61a9fSzX4o8uk43bJlS2nWrJlG3fDgwQNp0KCBVK9eXUlo3LlzJ12UTX387dChg4waNUpEPv3mLCwslONxRESEvHjxQnbt2iWVKlUy+HpR5H/1/urVqzUG6O/Xr5+UKFFCxo0bp3XjZ82aNQb/lDe1OXPmyC+//KKV3NyyZYt4eHgo9X5MTIycPn06XeyLagsWLJDcuXMrSdCRI0dKtmzZZO/evcoyO3fulGLFimm1MDdE6n1p/fr1GvX7wIED5bvvvpOgoCCtZO66deuUbWao51ZqU6ZMkREjRki/fv00pu/du1ccHByUa7PIyEg5fvx4utoX0xoTT5RuqCsmdQUXHBysPMFt27ZtGkmnN2/eKBf98+fPTzcn6iKfEmqenp7i5uamXGQ9ffpUpk2bJjY2NhpjIqUnV69elVq1akmmTJm0HpP69OlTyZMnj1bS0FBPjBIeVI4ePSply5YVkU8HU3Nzc2Xw4rdv38qff/6pPKkvPe2LBw8eFAcHB2nVqpVGl6Zu3bpJlixZZPXq1Votnwx1m8V39uxZadeunWTOnFlpgaZOMEVEREjhwoVl6dKlGu8x1HIldsJWqVIlmT9/vuzevVtjX/z48aNMmzZNNmzYoDyQIanPMDT3798XFxcXcXV1lZcvX4rIpwvfYcOGiYuLi0yYMCHR9xn6CeDr16/FyclJVCqVRrdptU6dOomPj49WOQyxHkm4H40dO1b69+8vIp8G4I5/of/mzRsJDw+XW7duScuWLQ1+O6m9f/9eWrduLSqVSmm5+/79e9m+fbs4OztL7dq1E31feimfn5+fWFlZiYuLi9LqVV33LV68WAoUKKCME6Rm6GVT/1b8/Pxk9erVsmfPHjE3N1eS8zExMbJ06VLlnNHQbzTEFxISIpUqVZIqVapoJC169uwpXl5eiSafRAx/m338+FF8fHxEpVJJnTp1NLqrinxqLZQvXz6t8w9DrBfjU+9TnTp1Ulrrbt68WSwtLZXz38jISHn16pXs27dPypUrZ7DnHvHFxcXJw4cPpVixYuLr66uMvSjyqduuo6OjBAUFaY0DKmL4+2JERIQ0adJEVCqV+Pr6isin7ajeLoGBgWJvb6/VwtDQy6UvTDxRuhD/B61uVfLgwQOpXLmy8mSt+C1JTp06JbVq1dIYnM4QK4HETmzi4uLk+vXr4uXlJS4uLhrJp6CgIFGpVFoXxYYmqRO227dvi6+vr5QvX15WrlypTI+IiJCiRYsafGsgEc2n8Z05c0bev38vwcHB8t1338mqVavEyspKo/nwnj17pFmzZhrjKhjiyVFS2+zIkSNSoEABadGihUbyqXv37hoXX4YqqXJdvHhRGjVqJObm5srYJSL/SwSoBws2ZGfOnFHuIg4cOFBWrFghIiJDhw6VKlWqiKWlpcbT20JDQ8XX11eCgoKUaYZ6UpswrtjYWDl48KBUqFBB3N3d5cWLFyLyKfk0fPhwKVq0qAwZMkQfoaZIYuv7wYMHUqFCBcmfP79s27ZN41i1YMECKVGihJJsM1SJHV9//vln8ff3lx07doiFhYXGvjhnzhyla4x6naSXY/Tz58+lW7duYmJiooylo04+ubq6ipeXV1qH+VUSK1tsbKwMGjRIcufOLUOHDlV+ZyIix48flwIFChjcgOgJHTx4UPn/mDFjZMqUKSIi0rt3b8mRI4dYWFjIkiVLlGWePXsm1atXl0mTJinT0ku9KPKpi3jDhg3Fx8dH43jcq1cvKVOmjAwcODDJhxIYisT2xYiICGnfvr1ky5ZN9u3bp1H21atXS6lSpQy2K39S1MNgtGrVSjZs2CBHjhzRuGkeExMjCxculHXr1mkkNwwxCZrYvnjkyBGpUqWK1K9fX3bu3KlM79evnxQoUEDGjh1r8NsssXX94MED6d69u5iammokeEU+dYEvWbKkwf/GDAUTT2Twtm/fLh07dpSwsDDp0aOHGBsby7Nnz5SLKBMTExk0aJCy/Pv378XX11d++OEHg6ys1eLHtmXLFpk/f77GWFQ3btzQSj49efJEfvvtN4NMXKjFPxitWLFCxo4dK2vXrlXukl67dk1q164tLi4u0rlzZ5k+fbo0bNhQnJ2dDbpcIiL79+9XBg7s1auXxolP48aNRaVSabS8eP/+vdSrV0+aNGli0Pti/G22ZcsWWbhwoQQHBytPWTx8+LCSfIo/mOnUqVMNepslPFGdO3euRsLz6tWr0rBhQ8mSJYv88ssvMnPmTKlXr54ULVrUoMsVGxsrDx48EJVKJb1795auXbuKhYWFMubFxYsXxcHBQUqUKCFXrlyR2NhYefjwodSpU0fKlStnkBf48cX/rYSHhytJl9jYWKV1YcLkU8+ePQ3+sefxy3Xv3j2JjIxU7tjfvXtXSpQoIZUrV5Y1a9ZIRESEhIaGyvfff2/w490dPHhQGT+sY8eOysDumzZtklKlSomZmZnMmjVLWf7NmzdSt25dpTWUoYq/ve7cuSPXrl1TXoeHh0uXLl20kk+///67/PjjjwZd34tolu306dNy48YNuX//vjKve/fuUqJECfnpp5/k+vXrcuHCBalZs6Z4e3sbdNnCwsLEzs5OqlWrJj179pRs2bLJpUuXRORTuWrXri25c+eW+/fvS1hYmDx69Ehq164tZcuWNeg6X0Rzm4WGhmrckN29e7fUq1dPK/nUvn176dChg0HXHwnrxfiDbEdHR0uDBg3Ezs5ONm3aJHfu3JFnz55JtWrVpEaNGgZdLpFP54zq/WrMmDEye/ZsEfn0YBNTU1MxMzOTtWvXKsu/fPlSqlWrpnEeaYhljL/NHj58KG/fvlVapR0+fFgqVaqklXzq2LGjNGnSxCDLo5awXPHHm3r27Jm0bt1asmbNKps3b5Y7d+7I8+fPpUaNGuliXzQUTDyRwdu4caPY2tqKp6en5MiRQ2N8oFOnTomzs7PUqlVLxowZIwsXLpSqVatKsWLFlPGPDPEkKX4FNXjwYMmaNat4enqKSqWSXr16KY/4vXHjhpQqVUrc3Ny0ngZk6CdJ6sdFe3p6StGiRaVu3bpy+/ZtEfn0hKm6deuKkZGR+Pr6KnckRQzzrrfIp/1oxYoVUrZsWSlSpIjY2Ngo5RH51PWzSpUq4uLiIr///rvMnTtXatWqJUWLFk03+2K/fv3+j73zjooi6f7+tAoYQDIoIBIUBSUjEpScQTBgXDGjmFFQxAgooihmkgEVFRUUzJgVA4oBXXPOGRMZBOb7/jHv1E7PDOru83u0Zh8+5+xZ6e6ZUzV1+1bVrRugrq6ONm3awMjICCNHjiRyl5eXB319fQwcOBBnzpxhfQftsjhr1izIysrCxsYGTZo0wZAhQ8iG/86dOwgMDATDMOjZsyd27txJclfRKot8zpw5AxkZGTRr1ozkuuPL2MWLF9G6dWuYmZlBR0cHdnZ26NKlC5FF2vsGAFFRUbC3t4ehoSHLcME3PpmYmBCj1Js3b6ithibM7NmzYWRkBENDQ8TExBDP3KdPn8LS0hLNmzeHiYkJevXqBRcXF+JlSVu/uFwuSktLYWRkBGdnZ/Tr1w8KCgqkyk9JSQn69+8PfX19rF+/Hu/fv8eff/4Jb29vWFhYUK83+EREREBfXx8tW7ZEr169cOvWLQC8MOrRo0dDRkaGbPYFQ4Jo1PfCTJ8+Ha1atYKamhp69OhBSp/X1dVh0qRJkJOTg5KSEnr27ImgoCCiG2nu271799C8eXO0aNGCyCL/Hbp16xbMzc3RqlUrtG3bFl27doW1tbVE6cV58+bB0NAQ1tbWGDNmDLnONz65u7uzvDKE01TQyowZM9CpUycoKipi5syZpOJZTU0NevbsCYZhoKmpiaFDh7KqtNIqi2/fviUekBMnToSMjAyp8FtaWoq+fftCSUkJr169wpcvX/Dq1St4eXnB2tpaYnQjXxatrKwwfvx41mFl9+7d4e/vzwq7k5Q5esaMGejQoQNUVVUxfvx4vHv3DgAvf+TgwYPRqFEjqKurY+zYsbCxsaFeFmmiwfDUgEQwaNAgNGrUCIGBgeRUjs/58+cREhICPT09eHp6YsSIEURp0668b968CQcHBxQUFKCurg779u1Dy5YtMWbMGGJpf/jwIbS1tTFgwIDf3NrvI7i4qaiowIABA3Dt2jVwuVzs3LkTrq6ucHBwIFWlHj58CG9vb/Tu3Rs7duwg30P7hNS/f38wDAMnJyeRtp49exaDBw+GhoYGHBwcMGzYMDIh0S6L/A1hYWEhvn79ipUrV8Le3h59+/ZlGZ9atGghUmGRNgRlsaSkBD169MClS5fw9etX5OXlQVFREYGBgaRa2I0bNxAUFAR1dXUSdiecOJ0muFwuampqyHgwDIOpU6fizZs35D7Ae8dycnKwePFi7N+/n2yqaJVFwUXbihUr0Lp1a8TFxWHy5Mlo3LgxJk2aRMbs3LlzsLOzg7q6Oiv5Ku36Y9euXWjTpg2ysrIQEhKCbt26oX///iR86cWLF7Czs0P79u2xefNmMmbCOU5oorS0FJqammjcuDFJYs/n8+fP6NWrF4yNjSEjIwNra2s4OjpSvdEXlMOMjAzo6elh586d2LNnD3R0dNC9e3cSdlxaWoqQkBAwDMPyBqUVwffjwoULMDIyQn5+PjZv3ozBgwejU6dOyMrKAsD7HcLDw9GpUydWiIxguDmNXLt2DYqKilBVVYWXl5dYGdu+fTs2btyIgwcPSpRe3LRpE1RUVJCamkoMok5OTuR+bm4u/P39YWZmxpJH2jfEu3fvhp6eHrZv347ly5dDVVUVgwcPxtWrVwHwPJ+GDx+ORo0asSIDaB0zgPebX7p0CQoKCmjWrBkpZMLXfRcuXICTkxNkZWXRvn17WFpaomvXrhKlG1VUVLB582ZMnjwZdnZ2cHR0JJ54eXl5cHJygr29PatADe2yuGvXLujq6mLLli1ITU2FgoICfHx8yEFzUVERJkyYAIZhiLcrQLcs0kSD4akBKuEvjvgv8pIlS7B8+XJoa2tj9OjRZJEuGP9cVlbGqvJGuxJYuHAhBg0ahCFDhrDaunfvXsjLyyMkJIR4Pr18+ZLKSYiP4ERy//593L9/Hy4uLiw31T179sDFxQWOjo5Egd+5cwdeXl5wd3cn+WloQzD/SGVlJVJTU7Fo0SLiSiwuXv3z58+s8aJdFrdv3w5PT08MGDCAtLWurg6pqamwt7dHv379iPHp2rVrEiOLT58+RWFhIcaOHcsq53vhwgUoKiqib9++xJBx8+ZN9O3bF5qamqxFEk3Ut2A7evQoGIbBhAkTRBL/CkPz2PG5fv06MZbx2bNnD5o0aYKJEycSb7UTJ04gODiY6j4Jj9m2bdsQHx9P/uaXB+/bty8J5Xr27BlMTU3h6uqK06dPU92/6upqPHz4EFZWVujYsSM8PT1x9OhR1jMVFRV4/Pgx9uzZQ0I/Afr14sGDB7Fo0SJW7sF3797B0NAQ3bp1Ixv7kpISLF68mPr+CMvimTNnMGHCBPL31atXMXz4cBgaGrKMT2PGjIGVlRUWL15MZa6x+vJw/fnnn9DS0oKbm5vIM8LvFM3vGJ/9+/cjLS0NO3fuBMAzYBw/fhxaWlos41NOTg6mTZtG9QZfuG1Hjx5leb6fPHkSurq6+OOPP1BYWAiA119fX1+oq6uTXK+0wl83FhYWQldXF+3bt4ednR1Zbwiyc+dOpKenS4QRlM+ePXuwaNEiVkL+PXv2oGvXrnBwcCDGp6NHj2Ls2LESJYsnT55keVjfv38fioqK8Pb2ZhmfBg0ahBYtWpB5gPZDL1poMDw1QB2CSkC4AsKOHTugpaWF0aNHEzdcACILXUlQAGvWrAHDMOjQoQNevnzJurdv3z4oKSmhf//+xMUToH9xNGPGDCgrK6Njx45QVVVlhaIBPKOau7s7jIyMSBz/w4cPYWtri4CAAOrKxgrKYnV1tcjJo42NDXr06MFq9+nTp4m7MUC/LNbW1iI8PBy6urro1KkT6x6Xy8XatWvh4OAANzc31qaDdlmcNm0a9PT0oKWlBRUVFVK2mM/FixehoqICV1dXcoJ/+/ZteHp6wsDAAFVVVVSNnaDsnThxAjt37sSTJ0+IESYnJ4eE6r5+/RoAEBgYSDaQksLly5fBMAyaNm1KNlj8cdizZw+kpKQwefJkkQU8jfIoKD9r167FvHnzMGjQIKxYsYL1XFpaGpycnDBgwACSj+b58+ewtraGlZUV8vLyfmm7f0R9m4j379/DzMwMrq6uOHbs2HffH5o3IlwuF58+fQLDMGAYRsTD8927dzAyMoKjo6PI2NC+YQSARYsWoXfv3vD398eQIUNY9woLCzF8+HB07tyZ5MOrq6tDaGgo2rVrh+XLl1OrF48cOYKMjAxWOoYLFy5AS0sLnp6exGtw1KhRpAAITX35Hrdu3ULLli3RpEkTohcBnt47ceIE2rRpAxcXF5HP0a4Xk5OTMWHCBDg6OmLevHms5/jGp6CgILK5r66uRu/evdGkSRNWURBaEKfXPnz4gHPnzsHU1BRdu3YVqcQneGAO0DlmghQWFsLQ0BBycnLIzMwk12tra7Fv3z7Y2trCycmJVZgAoFPnC8tiaGgoLCwsRHT+gwcPoKSkBD8/P9y/fx8Ab1yHDh0KhmGIN1sDP6bB8NQAtSxcuBB2dnbw8vLCypUryaJh586d0NbWxvDhw7Fnzx74+vpCQ0MDXC6X2kVEfQp3y5YtYBgGM2fOFDlJzMzMhIeHB5XKmo9g206ePIk2bdrgwIEDWL58OaysrKCrq0s2wXx27NiBSZMmsSbXx48fi4RQ0kRsbCzc3d3h6uqK7du3A+BtMNLT02FnZwd3d3fcunULHh4e8PT0pFYOAfGyWFFRgbi4OOjq6mLChAmk8grAm5iXLVuGkJAQiZHFXbt2wcDAABs3bsTGjRuhoqIiUuUS4LmCe3l5sTaLd+/eZSU3pQHhPFytW7eGvLw8TE1NsXDhQmLo3LNnD2RkZODh4QELCwsYGBiILGolgfXr10NKSgoRERFkbPi/wb59+8AwDJYvX/4bW/hjBOVxxowZUFBQgLW1NZSUlKCtrY0HDx6wnt+0aROMjIwwe/Zs0uenT5/C0dGReL7SgKAsZmRkIDo6Grt27SLerU+ePIG5uTk8PDxw6NAh1NTUoHv37tRXHBSnsx89egRNTU3Y2NiwDroAnpFNSUkJY8eO/VVN/McIymJsbCyUlZUxZMgQ2NragmEYEeP0tWvX0LNnTwwaNIjlATt9+nQ8efLkl7b9Z5k+fTpkZWWhp6cHhmGwZMkScnB54cIFaGtrQ09PDzY2NtDX15cIA6EgxcXFSE9Ph7a2Nnr16sW6V1tbi5MnT6JJkybEg43WNYhgu2JiYtC0aVP07t0bMjIyMDY2FjlEPnXqFJo1a4aoqCjy2aqqKgwaNIgYAGhB8D07dOgQMjMzSUgu30BoamoKOzs7YnwaOXIkqbBI65gJU15ejuTkZLRr1w6urq6sNUZtbS32798PfX19jBs3DgC9/RJsV2xsLKSlpREYGEhk8fTp06znHzx4AIZhEBYWRq69e/cOo0ePZhWeaOD7NBieGqAGYcuzoqIili5dCh8fH9jY2GD06NHEM2H37t2wsLCAsbExHBwciOKjUcEJTkb37t3DlStX8PbtW2J4SU5OJqeq9bmx07bhF27PmjVrsGrVKiQkJJBr/Ph1AwMDEeMTn9raWurHbNGiRVBVVcW0adNIfqdFixYB4BmfMjMzYWNjg9atW6Nbt25Ub/QF+3Xnzh08evSIbICrqqoQExODrl27IjQ0lHUqJ2jUpU0WBb3LAN6CLzw8XKyrtI+Pj4jxiQ+tGxHB9+Ps2bOwtbXFhQsX8OLFC0ycOBFdu3ZFZGQk+R2OHz+O0NBQTJs2jfpcd9+TpVWrVpENpHBC0rNnz1LbJ4A9Zi9fvsSUKVNw5coVADzDmaurK7p37y4ii+JCLWjqp2C/pk+fDhUVFZiYmKB9+/bo3bs3SZz75MkT2NjYoHPnzujQoQOMjY2pzlElKIeVlZWoq6sjv/vdu3chLy8PPz8/kp+Qj3BINe3cuXMHS5cuJYUIHj9+jHHjxqFly5bYtWsX69kHDx6Q34XGOU1QFi9duoSuXbvi/PnzKC0tRUJCAmRlZREVFYWioiIAvOID06ZNQ3R0NBlbWsdOWC/y/66oqMC2bdtI/iNBamtrcfXqVWr7BLB/74KCAowbN44UKjl//jzs7OzQu3dvUiGTj2C/aFwvChMREQFZWVkYGBiAYRjExsbi27dv4HK5OHHiBMzMzNCqVSt0794d2traVOl4YYRlkd/WyspKbNiwASYmJhg4cKCI8encuXNUy6Jgv65cuYKhQ4fi7NmzAHhRGIaGhujRowe5xufly5ci40Xbmph2GgxPDVDH6dOnMWPGDOzduxcAb0McHx8Pa2trBAcHE+PTkydPWIsjGpW3cPU6Q0NDNGvWDJaWlhg8eDDpC9/4FBUVJRJeSBv29vZITk4mfxcXF8PGxgYMw2DSpEmsZy9cuABnZ2cYGhpS7dFUH/fu3cPy5ctJMsuamhqsWbMGjRs3JuVu6+rq8OXLF1y5ckViZDEyMhIGBgbQ1NSEuro6YmJiwOVyUV1djejoaNjY2GDKlCkszyfh76CBYcOGISkpCQBvHN6/fw91dXUwDIOJEyeynuW7Svfo0UMiT6eysrIwfPhwTJ48mVz79u0bpk+fjq5du2LmzJnE+CS4yadRFgH2Ym3Dhg2IiIjAuHHjcODAAZSWlgIAli9fDoZhsHTpUrGyR1vf+KFJfDIyMiAtLQ1zc3NWvrv9+/fD3d0d3bt3FzFmAOwNGm3vHMBLxt+vXz9iTMvIyCAlpfnGp9evX2Pjxo1ISkqi0ojGR1AOlyxZgsDAQNja2mLOnDm4du0aAF4Ibn3GJ4BOA0ZoaCjJswLwPJIZhoGKigpOnDhBrj99+hQTJkyAvLw8du/eLfI9tG+qlixZgsmTJ7NyVQG84gRycnKIjo4Wm/eORlkE2L93SkoKJkyYAD8/P+zevZsY0bZt24bWrVsjKChI7HfQJo/z589n/Z2dnQ1TU1MYGxuzDiVPnz4NOzs79OrVixhHBaGtX+K4ffs2LC0tcfnyZbx+/RppaWlgGAYzZswg8/KDBw8wZ84czJo1i2ojqKAsJicnY/To0ejduzc2b96M6upq1NTUYP369TA3N2d5RwpCW78WLVrEysu6bds2WFtbw9TUlLVHuXnzJjE+CadpAOjVH5JAg+GpAao4duwYOnXqBE1NTZw/f55cLy8vx5IlS0j5WOGqKrQvjhISEqCkpITDhw/j8uXLWLZsGSwtLeHm5kYmo3Xr1oFhGOJ2Syv79u0T+f0fP36MPn36QE1NTcT9uaCgAMbGxujfv/+vbOZ/jOBCXfgEjm98Wrx4scjnaJtohYmPj4eysjKOHTuG48ePIzk5GU2aNCEhI5WVlYiOjoa+vj5Wrlz5m1v7fZYvX05O2vg5f+7cuQNzc3N06dKlXlfp8PDwX97W/4Tq6mr4+/ujRYsWInk8vn37hoiICNjZ2WHChAki+SNoJzw8HEpKSggKCoKRkRFMTEwQFBRENs0rV66ElJSUSP4P2ti1axfMzMxQV1dHjEVnzpxBQEAAmjVrJmLs3L9/P7y8vNChQwfqQju/x/bt29G9e3d4e3uzZG337t0ixidBoxntenHGjBlQUlJCXFwchgwZAicnJ3To0IGEyty9exfKysqwtbWlfryePn0KNzc31uaouLgY0dHRkJaWxurVq1nPP3v2DJMnTwbDMDh16tQvbu1/Br+6lJ2dHcvQBvB0h6KiIsLDw6k/0BNm2rRpUFFRwZAhQ+Dr6wtFRUWMHTsWDx48AJfLxbZt26CtrQ1fX9/f3dTvkp2djX79+rHe/+PHj6NHjx5o0aIFtm3bxno+Ly8P3bt3h4ODAzFsSwpxcXEICQlBSEgI6/rWrVvBMAwiIyPFzs+068Zp06ZBVVUVQUFB6NevHxo1aoRRo0bh5cuX+PbtG9auXQtra+t6K0jSQkZGBoKCglhtvHz5MpydnSEnJ4cNGzawnr916xY6d+4MW1tbMqc18J/TYHhqgCrev3+PKVOmQEVFRSR3Qnl5ORISEqCjoyN2w08rFRUV6NWrF2JjY8m16upq7Nu3D2ZmZoiOjmblL5EUS/qCBQswdepU0vZnz57B1dUVmpqaInkgbt++TfWEJI7Pnz8jJiYG0tLSWLNmDQD2RiopKQkMw2Dr1q2/q4l/m9raWvj7+4skTszNzQXDMKQUekVFBdLS0qgdM2FD87p16xAWFkYS8QueVv2MqzRtiPNyKS4uxqhRo6Cvr48VK1awvJq+ffuGMWPGIDg4mEoPmfo4efIktLW1WWW/k5KS4ODggDFjxqCyshIA75SyW7duVPft27dvRC4FZa6goAAODg7Q1tZmeT0BPC+20NBQat8zcSxZsgSdO3eGpqYmq/AFwNtkenl5wdzcnNpcQOK4c+cODA0NceTIEXKtoKAAAwYMgLm5OQmJvHXrFjw9Pak/6BJk27ZtpKJncXExIiMj0ahRI2RkZLCee/ToEZYtW0a1bqzv/Y+OjgbDMEhKShIpOrBgwQK4u7tTrTuEOXv2LNq0acNKWJyeng4TExNMnToVtbW1KCkpwbp16xAQEEC1PFZUVJD27dmzh4xDQUEBAgICYG9vj5ycHNZnjh49Sn1OSXHMmzcPDMPA1taWeIvz+7tt2zZISUmJ5NCknfz8fGhqahIDPMBbL6qqqhKv8rKyMixbtgwjRoygfsz47Ttw4ACZv27fvg03Nze4urqKyOL169cxaNAg6vslSTQYnhr4bQi/yHwF/fHjR0ybNg0WFhaIjo5mPVNWVoaMjAyqF+riFjgODg4i1WMAICgoCL6+viKfoXHxJzxe/PDAefPmiRiftLS0xG48aB23+iaVsrIyREREiF2oA7xTfhrHio+wXJWWlqJDhw6YPXs2AF6/+R5D48ePh7u7Owlz4kPjmAnn/AkJCYGJiQmioqLw/v17ALxwIEl0lRaUxefPn6OoqAhv3rwBAHz9+hVBQUGwsbHB6tWrRfIqCP8utJOZmQktLS2WAaOyshILFy6EsbExK0RGUvrGr8oXExNDrhUUFMDNzQ16enoixic+NL5n9enF9evXo1OnThgwYIBICPW2bdsQGhoqUQv1K1euoHnz5iwva4CX2NjExAS5ubkin5GE/hUVFUFaWhouLi7E46e0tJTMafxCGcLQqBuF9eKDBw9YHk5Tp06FlJQU1q5dK2J8khTdwYdvkH/48KFISHKzZs1w584dACCGeYBOeRTOo6OtrY1BgwaRa2fPnkWfPn3g4OAgsuEX9x00UV+7VqxYAYZhRLwKAV5lU9oPUIQ5efIkdHR08OLFC9TV1ZF+5+TkoHHjxkRnVldXU5sHFGC3KT8/Hx07dsTw4cOJUf769etwdXWFh4eHxMmipNFgeGrgtyD4Am/ZsgWzZ8/GjBkzSGniz58/IywsDF26dBExPvGhfaH+/Plz8ndERAQcHBxw7do11jMJCQlwcHAQWSjRhmCbHz58SNyF09PT0bhxY8yZM4dMOs+fP4e7uzsaN25MNsw0I9i3jIwMxMfHY86cObh+/ToJKZw2bZpEL9SfPHlCPGRmzpwJfX19XL9+nfVcREQEPD09f31D/yaC/Xr8+DH594wZM0gZXEHjkyS5SgsuSOfOnQtzc3O0bdsWxsbG2Lx5MwCe18LgwYNha2uLxMREkcS/tC5qxS3ajhw5gnbt2pGQCv4zRUVFaNKkiUjOGRr7JtgvfhL+lStXQlpaGgsWLCD3CgoK4O7ujvbt27PkllaEN41Xr15leaalpKTA3t4egwcPxsuXL3/4HbQg2Cb+v1+/fg1LS0usWbNGJAl6u3btWEZEmhHsG39NcevWLWhra8PDw4NlfJoxYwakpKREwktoRPC9nzVrFszMzNCsWTM4OzuzwqanTp0KaWlprF+/nvr8hHzq04tycnK4ceMGgL8MTLW1tWjTpg2ZC2hGuF+lpaVYs2YNrKysWLmpzp49i8DAQDg7O4s93KMRwb69fPkSd+7cYRll5s+fj0aNGrFyoQpDozyKk8WzZ8+icePGyM/PB/CXgamkpAR6enoioZKS0C8ul4vFixejW7duGDVqFDE+Xbt2De7u7vD29pYYWZREGgxPDfxWwsLCoK6uDjc3N9jb25MKEADw6dMnTJ06Fba2tqzylbQiqNzmzZsHR0dH4ir95MkTtG3bFgEBATh37hy+ffuGkpISODs7i/WEognhfgUEBLCqL23evBmNGjViGZ8eP36MSZMmUWkcrI+wsDAoKyvDx8cHrVu3RqdOnTBnzhyygI+IiJCYhbrgmEVFRaFv3744fPgwAODcuXPw8fGBj48PMcaUl5fD3d0dI0aM+C3t/VkE+zV//nzY2dmxwpqmT58uYny6evWqxLlKz58/H0pKSsjOzsamTZsQHh6ORo0aYcmSJQCAL1++YMiQIWjXrp1INSoaEfztN23aRMaspKQE+vr68PX1JeMF8IzXxsbG5CCCVgT7tWPHDhw5cgRVVVWkCEGjRo1YxqdLly7BzMwMffv2/R3N/WmEq9fp6uqidevWUFJSwrBhw0hy1qSkJHTr1g1Dhw6t15OLJgTHa+XKlUhKSiIenkOGDEGHDh1w+PBhMm8VFxejS5cuEqfzk5OTsWzZMpKL6vbt29DU1GQZn8rKyjB27Fh069btt7T3n7Bw4UIoKSlhz549OHDgAGbNmgUDAwPWGioiIgIMw2Dfvn2/saU/h+CYbd68mVWcwM/PD7q6uqxKx2/fvoWBgQH279//S9v5dxHs1/r163Hw4EEAvHVGYmIizMzMWManc+fOwdnZGePHj//lbf27CBtBjY2N0axZM9jZ2WHmzJnESDh//nw0adIEqampv6upfwthZ4BNmzaRA9VBgwbB0NCQGEIB3v6sQ4cOYgsS0IRgv1JTU5GdnQ2AN45LliyBra0ty/h0/fp1mJmZYcqUKb+lvf8LNBieGvhtHD58GGpqaqwEgsnJyWjcuDEphf7hwweMHDlSonKXzJgxA61bt8bOnTtZFTvu37+PTp06wdjYGHp6erC2toaxsTHxWKC9fzNmzICKigr27t1LlDSfDRs2oEmTJqywOz6SYHzav38/NDU1cfXqVXItIiIC9vb2WLx4Merq6lBSUoJx48ZJ1EI9IiICKioq2LNnDyuc6eDBg/Dy8oKsrCxsbW1hbGyMzp07Uy2LwpthdXV1ZGdni4R0RkREwNzcHFFRUSIed5JgfCotLYWTkxMSExNZ19esWQOGYcgi/uvXr4iJiaH+/RIct4iICGhoaCAuLg6fPn0CwNOLKioqcHZ2RmpqKnJzc+Hp6QkLCwuq+yYsj61bt8bmzZuJbqyqqsLq1avRqFEjVn6/27dvS4QcAjzjjLKyMs6fP48rV64gNzcXSkpKrPDwxMREdOjQQWK8ggCeB2vr1q2xYsUKVjinp6cn2rVrh5EjR2LRokVwcXGBsbExlR6tggjK4rRp06Cmpob09HSWJ9qtW7fQunVreHp6EuNTRUUFlbpeHF+/foWHhwfJtwjwDIObNm1Chw4dWPpSsJIirQiPWdu2bVnGwps3b8LW1hbq6upIS0vDpk2b4OPjA3Nzc4nSi61atcLKlStZBs/ExESYmpqyDIZ//vmnxOhFgJd3UFlZGbt378aZM2cwefJk2NjYYPjw4cRTPi4uDgzD1Bu6RQvCsqilpYXU1FQii/n5+ejRowc0NDSwdu1abNy4Ed7e3jAzM5MoWdTU1ERsbCyZo7lcLuLj42FjY4Pg4GByXTjEtYH/WxoMTw38NjIyMmBqaspKPgjwqm7JycmR6mjFxcUSE6Ofn58PbW1tnDlzBgDPLfXt27c4fPgwSktLUVJSgv3792PBggVYv349tWWm+bkT+ONy6tQp6OjoECNhVVUVXrx4gf379xODBr9s7Lp1635Lm/8T1q1bB0NDQ3z9+pXIWEVFBcaMGcNa6EnSQv3YsWNo27YtCgsLAfCSH798+RInT55EZWUlKioqsGXLFsydOxeJiYnUyuLNmzdZf585cwZ6enok2eW3b99QVFSE3NxcIq+RkZHQ0tIiFSJpHjPhtr1//x4qKipkI8XlckkuroCAAIwZM0YkHIjmxR+fxYsXQ0VFBYWFhaS9/P+/ePECHh4eMDAwgJGREby9vYkRlMa+Cc5XS5YsQatWrVBQUMC6zm83vypfREREvd9BK0OGDMGkSZNY1+7evYvmzZsjMjKSXMvOzqZynMSRmpoKVVVVVuitYKWpxYsXw8/PD926dcOwYcOolkNh1q5dCw0NDaLzAZ6c8b0Jb926BS0tLVhYWKC4uJg8Q6N+FG5TVVUVDA0NRSqSlpWVwc/PD8HBwSLfQdtcJo7ly5dDVVWVlUicz7t37zBq1Ci0a9cO5ubmCAgIkBh5TEhIgKqqKq5du0au8ceDXwnN3Nwcfn5+rM/Rrhe5XC6+fv0KNzc3Vh6nyspKJCYmwtzcHBs3biTX09PTJUIOAV5+KnV1dVZINZ9nz55h4sSJaNWqFbp06QJ/f3+JkcVly5ZBRUVFrCwCwKpVq2BnZ4c+ffqwPAxpl0VJpcHw1MAvQdwLvGPHDkhJSZHkpHwldufOHWhqahLjzfe+gzYOHz4MAwMDfPnyBQUFBZg+fToMDAwgLy8Pd3d3kZLaAH1KOzo6Gh4eHqxrZ8+ehZGREe7cuYNbt25h2rRp0NHRQdu2baGpqUlORg4dOkT9JCtOjtLS0tCuXTuyQOfL4osXL9C4cWOcOHGC9TyNC3Vhjh8/jk6dOuHp06e4c+cOIiMjoaOjA01NTRgYGBCPE0Fok8WkpCTMmDEDwF/jlpOTAy0tLQC8HE4zZ85Eu3bt0KRJEzg5ORH5S0xMpK4/wgjK4tOnT4ncDRs2DK6urnj69CmAv+Rt8ODB6N+//y9v539KRUUF+vbtSxbqT548wd69e+Hp6Ylp06bh6dOnqK2tRVFREZ4/f076S5sumTp1Kgml4HK5qK6uRkBAAMlD+PTpUxw4cAA9e/ZESEgI7t27B4B38k17UllhvVhdXQ0bGxuWVwLf4BkbGwtra2sRHUL7+wbwvO7GjRsHgOdtt27dOhgbG8Pd3Z2VO0fQGEWbHALA0KFDcfnyZQB/6YfQ0FCSvPnBgwfYsGEDLC0tYWFhgS1btgDghZLQXglNWC+WlJQAAIKDg9GzZ088evSI9Xx4eDjLWC0pVFZWIjAwEHFxcQB4Y7Zjxw64uLggMDCQePO+efMGJSUl1OrF8PBwkjMS4OmBIUOGEC/IJ0+eYNeuXXB0dMS4ceOQl5eH2tpaLFmyBMOGDaNaFgHR9V5tbS26dOkicpgAAK6urhg4cKDIddrGTBAul4tv376hT58+mDNnDgCe18/OnTvh7u4OPz8/4j359u1blJeXUyuLsbGxrMiF6upqDB06lLxj/H5169YNw4cPJ0a2qKgojBkzhnpZ/DfQiNNAA/9luFwup1Ejnqht376ds2XLFg6Hw+G4u7tzunXrxpk4cSLn+fPnHCkpKQ6Hw+E0b96c07x5cw6Xy2V9D/87aAGAyDVzc3POixcvOJ6enhx3d3fOly9fOPPnz+fk5uZyCgsLOY8fPxb5TOPGjX9Fc3+aXr16cWRlZTlv3rwh12RkZDjNmjXjjBo1imNvb8/58uULJzo6mpOTk8Np2rQpJz8/n8PhcDje3t6cJk2acGpra39X87+LoCymp6dzTpw4weFwOJwePXpwPn36xJkxYwaHw+EQWSwuLuZ06NCBo6yszPoehmF+Yat/jDhZbNy4MUdKSoozZMgQTrdu3TgfPnzgzJkzh7Nr1y5OdXU158yZM2I/QxMqKiqc9PR0zqtXr8i4WVhYcKSkpDidOnXiuLm5cT58+MCJiori3L9/n5OXl8fZv38/h8PhcMaNG8dp3Lgxp66u7nd2oV4EZTE6Opozffp0Tm5uLofD4XA8PDw4lZWVnOXLl3NevXrFYRiGU1VVxXn9+jVHU1Pzdzb7HyElJcV5/vw5Z//+/ZyDBw9yxo8fz1m2bBlHTk6Ok5GRwYmLi+M0btyYo6KiwtHW1uYwDMPhcrmcJk2a/O6ms7h48SInLy+Pw+Hwxq+uro5TU1PDefLkCScpKYkzceJEzqpVqzhVVVWce/fucSIjIzk1NTWcKVOmcM6cOcNhGEbsu/q7EZTFy5cvcz58+MCRlpbmDB06lHPixAkil9LS0hwOh8Np1qwZp3HjxhxZWVnW99CmP8RRWlrK2bZtG2fJkiWcQYMGcfbv38/x9vbmtGjRgpOcnMz5+vUrh8Ph9ZHD4elW2uSQw+HNQYcPH+ZwOByyVmrRogXn8ePHnNDQUE5QUBDn0KFDHFtbW46dnR1n5syZnNevX3NMTU05e/bs4TRq1EhkjUUDgrI4b948TkhICOfixYscDofDGTJkCOfMmTOcpUuXcm7dusXhcDic8vJyzqVLlzh6enpk3pYUmjZtypGVleVs376ds3HjRs6YMWM4GzZs4HTo0IFz9+5dzpAhQzgcDofTqlUrjpycHJV68cuXL5y7d+9yqqqqOBwOh8y3L1684Bw+fJizefNmzujRozmpqakcDQ0NzuXLlzlJSUmcxo0bc8aNG8dJS0ujVhY5HJ488td7T58+5Xz79o0DgKOnp8cpLCzkfPjwgaXTbW1tOSUlJZyamhrW99A0ZsIwDMORkpLiKCsrc06cOMFZuXIlZ/To0ZyNGzdytLS0OEVFRRw/Pz9OXV0dR01NjdO8eXMqZfH9+/ecw4cPc8rLy8k1aWlpzsePHznbtm3jZGVlcUaPHs1Zt24dp2PHjpz8/HzOokWLOBwOT9ckJydTLYv/Gn6n1auB/y3Cw8PRpk0brFy5kuRe2bp1K1xdXdG9e3ccPXoUR48ehY+PD6ytrak+PRW0in/69Anl5eWkisrDhw8xf/58HDhwgJzU1dTUwNramvpYb4BXpUNXVxcrV65kXT9x4gRSU1NZ/fr69SvMzc1x4MCB39HUf8y0adNIvHdRUREAXmiavLw8AgMDcejQIeTn58PHxwc2NjZUn4IItq20tJQkywV4uauWL1+OPXv2kPDJoqIimJmZ4dixY7+6qX+bsrIy9OnTB2lpaeRabW0trl27hrlz52Lv3r2kX6WlpbC1tcXJkyd/U2v/GTNnzoSysjL279/Pykm1YsUK2NraQkdHBz179oSVlRU6depEThhp9Z6p7125ePEiOnToADU1NcyZMwfnzp0DwAttkgRvhbq6OvTv3x+TJ09mXd+6dSvs7e2hqqqK6OhoEgI6e/Zs9OvXj/UsjWMm2KbIyEjY2toiOTkZNTU1uHXrFgYMGABHR0eS0PjTp0/w8vLCgAEDqOwPn+/p7AEDBsDa2hoJCQkklPf48eOwtrZm5cKjEf5vnpCQABcXF9a9W7duYezYsbC2tsaKFStw69YtAMDu3bvh5OTECq+jndmzZ0NNTQ3Z2dmswgNHjhyBlpYWunTpAmtra9ja2lKfnxCoXx6PHDmCPn36QFlZGfPnzydebBs3boSPjw/xsKSZ4OBgODo6sq49efIE5ubm0NPTQ0xMDPEsWb16NVxcXFj9koQxmzt3Lrp3707WFw8ePIC8vDwGDRqEp0+foqamBpWVlejWrRtCQkJ+V5N/ivpkcffu3Rg4cCDU1NSwYMECklojJSUFPXr0oM67SRyRkZFwdnYmBTAA3ljZ29tDS0sL0dHRKCgoAMB7x5ydnakPO/630WB4auCXsGHDhnpjh7Ozs9GnTx9ISUnBxMQErq6uVMcOCyrtuLg4uLm5oUOHDpg8eTKJ0+c/U1VVRRbqVlZWVPZHEL7STUtLQ5s2bVgVwwT59u0b3r17B19fX9jY2FDfL0FSUlKgoqKCq1evimx2CwoKYGRkhLZt26J9+/ZwdnaWGFlcsmQJnJycYG1tTcItBPn27Rs+fPgAPz8/2NnZUdkfcUyaNAlGRkZkcSC8MKiursb79+/h5+dHvcFamKtXr6Jjx46sUE7BMT1//jyWLFmC0aNHY/78+dTm4eIj2PYTJ06QCnZ8g1p1dTUr4XFdXR3c3d2pX6jzuXDhAlRUVEQqZr17945VSAIAvLy8xOadoZXo6GgoKyvj1KlTJBEwwMupNmTIEDRv3hwdOnSAkZERTE1Nqd7oC8rh9u3bERkZifj4eJaxnW+wBni60cvLCz179qSyP+KoqqqCtrY2K9cWwOuL4OHDt2/f4OfnJ1F9u3v3Ljp27ChyoMXX7Tdu3EBaWhpCQ0OxbNkyidKL+/fvx8aNG7F582ZWewWT3AOAm5sb9RWP+fJ048YNODk5YefOnaz71dXVrEI0NTU18PLywrBhw35pO/9T5syZA3V1deTk5LDG6cqVK1BWVoaFhQWsrKxgZ2eHTp06SYxu3LNnD9LS0liJ+WtqaliGXgDw8PDA4MGDf1kb/wn83zo/Px/Ozs6kCIsggrJYV1cHDw8PDB069Fc1sYH/T4PhqYH/KnxlMHr0aIwZM4Z1TXjTf+/ePbx9+5YoRloXEXz4ngqbN29GcnIyunfvDisrK+Tn5wPgTbqrVq2CjY0NbGxsqDZgCPP48WMEBgaiX79+5NQU4Cnr6upqLF26FJ6enrC2tpaofgHAuHHjiNcCX8YEJ+Py8nI8fPgQd+/elRhZjIyMROvWrZGQkICcnBy0bNkSAQEBJH+a4Jh16dJFIsZMcNFmZGQENzc38jd/PKqrq7FlyxZ0794dXbt2lYh+CXL+/Hm0bt1aJIE6wJNJcXJHa9+Eq9e1adMGRkZGMDQ0xMCBA4knEACUlJTgwIED8PHxkZjKnlwuF+Xl5Rg1ahT69euH27dvizzz9etXnDhxAj4+PujcuTP13ml8Xr58CVtbW9bGUbDNRUVFOHfuHJYvX46MjAwigzTqReEKTa1bt0avXr3g5uYGS0tLrF27ltwvLi7G2rVr4eXlBRMTEyKHNHu4An/pgJSUFFhbW2PHjh3kHr//JSUlyMrKgqenp0T1DeAZ5Fu1akUKzAiOaVVVFSv/Fh9J0Yvq6uro1q0b5OTk0LNnT+Tl5ZH7JSUlOHLkCNzc3FhjRrv+4Hsme3p64vnz5wDYbebLoq+vr0R4pwny4MEDGBoaYs+ePazrfHl7/fo1Vq9ejYiICCxZsoRqI6i4CrPdunWDuro6nJ2dUVhYSJ4pLi7G8ePH4ebmJjFzNJ+AgABYWVmRwwXBsSgrK8OuXbvg7e0tcf36t9BgeGrgl9CrVy+xpzdVVVU4duyYyEtP++Jo3759MDIyIh5OR48eRdOmTWFubg5TU1Ny/dq1a0hISKB6oV4fmZmZsLW1xahRo1gVgABeWNrKlSslrl+1tbWwtbVlJWjmy15VVVW9BgCaOXToEIyMjIh3Wm5uLlq0aAEFBQXY2toSD5MDBw5g6dKlVC+MhOH/9mfPnoWmpiZ69uzJul9RUUFkUZL6xSc3Nxfy8vKk6IBgtbpjx44hMzOTevkTZsmSJdDU1CShdDNnzoSsrCw8PT2JUf7KlSsICgpiVcaRlHHbv38/TE1NERYWRpL/8ikoKICnpyd69+4tUUbQFy9eQE1NDbt37xa5V1VVxfKA4kN7v5KSkqCrq0sMnqmpqZCWloaOjg5Jcv/582dEREQgKChIIvXHo0eP0LdvX3h7e7NO+LlcLl68eIHx48cjODhY4vp2+/ZtNGnSBHv37gXwV2VPADh58iT27NkjUtmTdhISEqClpUVC6fhVgL29vYnx6cKFCxg3bhz69u0rMWPGXz+9fv0aqqqq6NevH8ubkMvl4uHDhwgKCkKfPn0kpl98Ll++DFVVVTx+/BgArz/8PldWVoqdn2nXjcuWLYOGhgZJwr1z504wDAM7OzsinxcuXMCoUaMwYMAAiRkz/lgUFxdDT08PXl5erL0ll8vFzZs3MX78eImUxX8LDYanBn4J4eHh0NDQEAlHePPmDQYNGiRSwY52rly5gilTpgDgbeiVlZWxdu1aHD9+HK1atYKFhQVOnz7N+gyNk5E4K7/gtQ0bNsDBwQEeHh4ibu98ZU1jv75HTEwMunbtSjbBfO7fv48ePXqIGNlo59ChQ1i+fDkAniFDSUkJqampuHv3Llq2bAl/f3/i+cRH0sbs27dv2Lt3L7S0tGBjY4M7d+6QnGqCiwZJ6xcAdOvWDcbGxqyNVEVFBby8vDB79uzf2LK/z/v379G7d29STnr//v1o2bIlQkJCYGZmBjc3N1Lq/enTpxLjUShMSkoKdHR0MGnSJJEy6Pfu3ZO4fj1+/Bht2rRBUlISAPZ7dPbsWcyfP58VvkU71dXVmDx5MhYtWgQA2Lt3LxQUFBAdHY2hQ4eiVatWREa/fftG5jxJ1B+XLl2Cm5sbPDw8sG7dOta9oqIiiesbl8tFRUUF/vjjD9ja2uLUqVPkXk1NDVxdXTFx4sTf18B/wKdPnzBu3DiSq3DXrl1QUFBAVFQUtLW10b17d5w/fx4Az/uQ1oph9cGXrStXrkBeXh49e/bEjRs3WLL3/v178pykyCLAm6cUFBRIVUjgr/YfPnwY+/btk6jDoaKiIkycOJH0Z/fu3VBQUMCKFStgYGAAOzs7YpCiucJsffDH4tKlS9DU1ISrqyuePHlC2l9ZWYm3b99K3KH5v4kGw1MD/1X4SquiogJmZmYwNzfH7du38e7dO7x9+xZeXl6wt7eneiKqb1L5+PEjKisr4ebmRsrGAryNpI6ODvWxw4L9evbsWb33Dh8+jPHjx0NGRgYzZ84UieOXNPhJjoOCgkjOjxcvXsDf3x/du3eXOFmsq6vDs2fPUFZWhu7duyMqKgoAL57d2NgYDMNg5MiRv7qpf4ufcXOura3F/fv3YW9vD0tLS0yYMAH5+flUJ6X+Xr/4986fPw9TU1Po6OggLS0Nq1evhoeHBytUS5LIz8/HmzdvUFhYiDZt2hDvkpiYGDRv3hyWlpas0ts0Ltrr0wHCRnlHR0c4ODhgw4YNIs/S2K/vERkZiWbNmrHyjZWXl8PHxwfDhg2jOhRBXNs+fvyIR48e4dGjR2jfvj2WLVsGADh48CCaNWuG5s2bIyMj47vfQQM/I0eFhYUICQmBgYEBgoKC8Pz5c5ahkNa+fY9jx46hZ8+eaN++PRYsWIBFixbBxcUFxsbGEqcXq6urSe6069evQ09PDytWrADAy0EmLS0NW1tbXLt2jXyGxjETlkXBv/ntvX37NvT19eHu7o64uLjvfoZ2uFwuvn79ir59+8LT0xOHDx8m92pra+Hm5kZSiEgKtbW1yM3NxYcPH3D9+nW0a9eOFBLatm0bGIZBu3btSJgrQKcs/sw6/ebNm+jcuTPMzc2xatUqVo4nQLJk8d9Eg+Gpgf8TfkYxPXz4EHZ2dlBTU4OWlhbMzc1haWlJde4BwTY9ePAABQUFePv2LVn4PHv2DJqamti2bRsA3ol///79sXv3biqVtThmzJiBwMBAkXAKwfbX1NTg2LFjGDx4MOzs7DBnzhx8/vz5Vzf1h/zsb378+HHY29tDT08PWlpaMDExgbm5ucTI4u3bt3Hv3j1W/q3nz5+jXbt2OH78OABevpnhw4fj9u3bVBvTBHP/LFy4kJWDpT7Wr1+PCRMmQEtLC2vXrsWrV6/+m038r1JXV4enT5/ijz/+QKdOndClSxcMHDiQ+lCtH70jCxYsgJ+fH6qqqgAAiYmJcHV1xbx586h8v/gIVrgRXHzzEWz7xYsXsXDhQigqKqJ3794IDw8Xm3/md/MzBtDi4mKMGjUKDMMgODiYVKqSpGS51dXVqKmpYbUzIyMDFhYWZL46ceIEqZRJ67sljvj4eGzfvr3e+0VFRThz5gysrKzg5uaGbt26Uan7f9QewbG7fPky5s6dCx0dHTg7O2PIkCHUh+YK6zZhz4qVK1fCycmJyOOGDRsQGBiIoUOHUq0XBQ2Zgl5ogvDb//79e8yePRuOjo5o3749YmNjcefOnV/RzP8KeXl5cHd3R5cuXRAeHo74+Hg4OjpSbwStTxb515OSkuDs7EwMMtu2bcPEiRPxxx9/UKc36iM5OfmHlUjDwsLg7+8PTU1NLF26lHXw1cCvp8Hw1MB/BD8G/++QnZ2N9PR07Nq1i2p3R+Ey06amplBUVIS7uzuGDBmCsrIylJaWws/PD56enti0aRPc3d3h5OREFDuNCwnBfuXl5cHCwkIkXKS+z1RXV6Oqqgr37t37r7bxn/B32/T48WOcO3cOCQkJyM7OlhhZnDNnDkxMTNC+fXtoaWkhNjYWdXV1qKyshLa2NgICArB79264urrC1taWyCCNC4lXr15BRkYGQUFBmDp1KmRlZb+7QBXuA78gAW1MmjQJR44c+duf+/jxI8rLy6l3bxfUa+vWrUNkZCSCgoJw+PBhsqGaM2cOzM3NifGmZ8+eWLVqFekbjbrxyJEjGDduHEpLSzF+/Hi0bdtWbIiZsAHm1atXSE9Px/z586kLG/+7uXBSUlLQv39/BAQEICwsjOo8GMJVPQcOHAhzc3MsWLCAhHRmZ2ejVatWyMrKQklJCXx9fTF58mTqQ9AE+5aWlgYNDQ2Sf+VH3L59G9u2bSPhW7Tg4+NTb6VcQYTfr/LyctbfNMoiwB6zlJQUTJw4EZ6ensjOzibz1Jw5c2BpaYl79+6hvLwc/v7+SElJEfsdtJCVlYUBAwbg27dvCA0NhYqKioj3CB9B4waXy8W6deuwcePGeo1VksKVK1cQHR0NAwMDuLm5YejQoVQbQYVlccyYMfD398emTZvI4cj06dPRoUMHvH79Gl+/foWfnx/xfgLo1I2C/Vq9ejUYhqnXkCTY/rKyMmzduhXJycliq6s38OtoMDw18I9ZsGABgoKCWIrge5NmfUqMRuUmSHx8PFRUVHDq1ClUV1dj+PDhkJWVJYu6rKwseHl5oX379vD09KTaa0aQtLQ0jB07lpT8pr2932P27Nmws7MD8J+dytMui7GxsVBWVkZeXh4+ffqEkJAQ1sR7/vx56OjowNjYGM7OzhIhi/n5+ZCSkoKcnBxJsk37OHyPFy9eYOzYsSKL0Z/xOhF8huYx4zNt2jSoqakhIiICvXr1goGBAUJDQ8HlcpGTkwNra2sYGBiQ6na0V3lLSEiAsbExLC0toaysLNbjSRiaZXXUqFFYunTp3/6csOzSuLESZMaMGVBRUcG6desQHx8PExMT2NnZobi4GA8ePMCgQYOgqKhIdCPNHlzCXLhwAaGhoSR/0/faTLMsAjyDPN8Q+rO/vWBicUAy9OL06dOhoaGBKVOmICIiAgzDIDIyEgBw48YNKCkpwcDAQGLk8fz582AYBsbGxlBQUMCNGzcA0Nven8HNzU0kz+fPUFNTw3rPaNeN06dPh6amJiZPnoyFCxeCYRjMmjULAO/ARE1NDa1bt4auri5LFmnn9OnTSExMRE5OznefE5ZRSZbZfwsNhqcG/jHPnj0jSpd/ugj8eGHAv0+rAhDcBJaVlcHX15ckIj18+DBkZWXJIpDfl2/fvuHt27fUeyoIMmDAADAMA0tLS3z9+hUAvWPyIz59+kR+8zdv3gD4uQUq7ZOSYHuqq6vh7+9P8pLk5ORAUVERycnJAP6SuYqKCuqTQgqOzaVLlyAlJYUWLVpg2LBhYp8B6BsbcQi3MT09Henp6fXe/95nad9EHjp0CLq6uiQRaW5uLpo0acIKBzp8+DCWLVuG+fPnU12MQFDWAgICwDAMBg0aVO+pvjhok8+qqiokJSWJhGz+jF4Ul7uFVgoLC9GpUydyEHTs2DE0bdqUJHIGeBW3jh8/jm3btlHt2SoIl8tFYWEhZGRkIC0tTXJUSSLCMrd06VLk5OT81BjQLn/CHD9+HG3btiV6sbCwEAzDkHQMAHDr1i2sWbMGa9asodqjkMvlkvelf//+YBgGfn5+ZL0oycydO5eEgf8sklZ9+9SpU9DR0SEePnwD4ubNm8kz7969Q0JCAtauXUu1LApSUFCARo0aQUZGhhieaB+LBv6iwfDUwD9CcPOwd+9eGBgY/JS7sKDi/vTp03+vgf8QwXa/e/cO1dXVcHZ2Rn5+Pvbv3w9ZWVmy0a+urkZqaipOnDhBvadCfYs3vtv0smXLJHIxIVjaFuBVi2EYhoQOfm8sBD/3/Pnz/14j/yGCbX/y5Alqa2uhpqaG06dP4+TJkyxZrKqqwuzZs1n5koS/g0ZycnLw9u1bvHv3DqdPn4aCggL++OOP392sfwSXy2Ut2MrLy2FnZwdHR0dkZWWxnhP3WT7p6ekiVQhpQNhgtGXLFjg5OQEAduzYATk5OVIVrbi4GJcvX5Y4Y1plZSViY2MRGRkJKysrTJgwgZTRpv1dEkT4d1+/fj1Gjx6NyspKAD+vF2lEWIYuXbqE9u3bA+Dpfzk5OaIXS0tLsWvXLpG5jXY5FGTLli1QUlKCn58f8QiVdNzc3KCgoIDc3NzvbnIFZXH79u3Izs7+Fc37Wwi/S7t374a7uzsAXptlZWWJXvz69SsrgTgf2uWxqqoKW7ZswaZNmyAjI4PBgwfj5cuXYp+VJD0JAIsXL8a+fft+6lnadaM4WXR1dQXAi8wQXDN++fJFbOgu7bIIAG/fvkVCQgIUFRUxadIkcl3SZO9/lQbDUwN/G8GX+/nz53jz5g0GDx6M7t27sxIDf89jYfny5TAzM2Mlcv3dCLZv/Pjx6NOnD968eQNXV1d069aN5V0C8Dy+3N3dWR4NNCI4Dk+fPsWLFy+IVxAAjBgxAu3atUNKSgpV4/EzCOYv+fLlC4qKitCnTx8oKSmRSVXcZCQ41klJSfD396cyVxAAREREICAgAGVlZZg4cSICAgLQvHlzrF+/njzz+vVrkmdMEuByuSgoKICMjAxev34NgDdOhw4dgoKCAqsi5Lhx47B169bf1NKf58mTJ+TfiYmJuH//Ph4+fAhfX1+4urqyqkEKyp/gv9euXQuGYXDw4MFf0+h/QEpKCj5+/IiUlBT4+/sjLy8PcnJySExMJM/s3LkTYWFhKCoq+o0t/XvExcVhxowZ5O8VK1bA3NwcEyZMYI2toHcvrQjrvJkzZ8LCwgLTpk37rvFJUBZTUlK+m8z6dzN//nzk5ubizJkzsLa2xqZNmyAvL082+QDvxD8oKEgiEhsLjofw5m/9+vVo3bo1wsLCiCFUUhA0tKxevZq8P7169YKqqioOHTok1vgkKIvJycmQl5f/R3nzfhULFizAvXv3sHv3bnTq1AlZWVlo2bIlSx4zMzMxYMAAvH///je29O+xatUqjBgxgvx99uxZSEtLY/DgwWTuBvDDkCca4XK56NevH5o2bYqjR4/+8Fk+u3btoq66s2D74uPjcfHiRRw9ehRmZmZYv369iCzm5OTAx8eHNYY0Up8x6dOnT4iPj4e0tDSp5Py95xughwbDUwN/i8zMTKK8pkyZQvLq3Lt3D0OHDoWtra1Y45PwglZJSYnlevy7EWzfq1evYGlpiby8PAC8mHwNDQ10794dAM/Y8eXLF/j4+MDBwYHqEwLBfs2ePRvm5uZQVFSEvb09S1kPHz4c7du3x9q1a/Hly5ff0NK/z7Fjx7BkyRIAwJgxY+Dt7Y2amhq8e/cO/fr1Q8uWLcUanwR/k9TUVDRv3pzlkfK7EWzr2bNnYWlpSTy4NmzYADU1NQQEBJAqhB8/foSPjw+6d+8uEbLI/39paSn09PRw7tw51jN845OVlRXs7OzQrl076l2/r1+/DoZhkJOTg2nTpkFZWRkPHjwAwKuM5uXlJWJ84idf5ZOSkoKWLVtSd6ovKI8rV64EwzB49OgRXr58CWVlZTAMwzJQVFZWwtvbG8OHD6f+hJhPXV0dgoODRUpjr1ixApaWlggODkZeXh48PDxgaWn5m1r5c1y8eJGEkMyZMwdbtmxBZWUloqKi0LVrV0ydOlWs8UmcAXTXrl2/tvHfQbCtO3fuhJSUFP78808AgKOjIxiGwfLly8kzlZWV8PHxQa9evajfjAi2LykpCUOGDEFQUBAWLlxIricnJ0NDQwNhYWEsQyjN3L59G/r6+pgxYwbCwsIgJSWF27dvk/v+/v5ijU/CiZHl5eWpmqMB9vuyadMmyMrK4ty5c/jw4QNcXV3BMAwWL15MnqmoqECPHj0wePBgidGLADBy5Eh4eHgA+Gtczp07h6ZNm2LgwIE4dOgQevToAUNDQ+r7de3aNdKH5cuX49q1a+ByuRg1ahTk5ORw+PBhsZ8TPqiUk5PDiRMnfkmbfwbB92XDhg1QV1fH+fPn8fTpU3h4eEBaWhoxMTHkmYqKCvj7+1Mvi4L92rx5M+bNm4fRo0fj0qVLKC8vR3V1NeLj4yEvL4/o6GjyLM19aqDB8NTA3yQmJgYMw8DT0xMtW7YkCz+At8HiG5/4OZAAdrwwf3NFy4KWb2ThK7iFCxeiZ8+e+OOPP1BRUUEUWGZmJmRkZGBtbQ0bGxt0794dpqam1Jc857NgwQIoKSlh37592LFjB6Kjo9G8eXNMnjyZPBMcHAw5OTns2bPn9zX0J/n27RuGDBkCS0tLuLi4QElJCbdu3SL3BY1PV65cAVD/Rn/37t2/vP3iuHnzJuvv9evXY8yYMazTRoD3DhoYGMDCwgKenp6wsbGBubm5xMiiYJUwfX19rFq1SuSZO3fuYNSoUYiIiKA6NxDfQ7CiogILFiyAtLQ05OXl8ezZMwB/6T6+8cnNzU3sBoo2vchH2Ai6Zs0aln7YuXMnlJWVMWrUKBQUFCA3Nxeenp6sMtM0LgLFGSKWL18OY2NjlJWVsTwpk5KSYGdnBx0dHdjb2//tKnG/kjdv3qBRo0YYMWIExo0bB3l5eaJXKioqMHfuXBHjU21trUQYQPlkZWVhw4YNSE1NJdeePn0KS0tLGBkZISkpCStXroSbmxs6depE5JB24xPA825VUVHB5MmT0aNHD7Rv3x5du3Yl91NTU6GtrY1Ro0ZR7anA9+h59+4dli9fDiUlJcjJyZHKs/yqWgDP+KSmpobc3FyRxMapqalU6kVBjh8/jsmTJ2PLli3kWlpaGqysrODt7Y2zZ88iMzMTXl5eEqkXMzIyYGtri8rKStTV1ZH25+fnQ0dHB+bm5rC1taU+Qfr169dhZmaGWbNmYdKkSWAYhlUJefjw4WKNT8JGUAUFBeqMoHzy8/MxZswYVg6ntLQ0GBsbo0+fPti3bx8yMzNF5mjadWNYWBhUVFTQo0cPmJmZQV1dHfPmzcOHDx9QUVGBpUuXQllZGeHh4b+7qQ38BA2GpwZ+yKxZs1jlKjt37ozGjRtjzpw5ANgTzf379zFs2DB069aNdfoI8E5RaVpEREdHk5McgLcAX758OZo1a4bOnTuLJB589OgRoqKiMHfuXKxfv15ikpSWlJTAw8ODFQpTXl6O9PR0tGzZkuWhtmjRIio3+HwWLFhAPNEAwMrKCgzDiJ1w3r17h/79+0NRUVGkegnfdZ8WWUxKSiJhPvzff+jQoWAYBqampiL50A4ePIj4+HhMmTIFqampEpMUMiEhAR07dkRQUBAmTpwIX19fRERE4OnTp9/9HI39Cg4OhqmpKQkn27BhAxiGYXmKCCZnvX//Pnx8fGBiYsI6LV2xYgUUFRWpkUUALMMEwKusxTAMmjVrhr1795LrX79+RVZWFnR1daGpqQkLCwsEBARIjBE0JycH+fn5KCoqwqpVq2BjYyNW1h4+fMg6LadNHq9evUp+8+vXr0NaWhqysrIk5xt/HCoqKjBv3jzY2NggPDycZQAA6NvoDx06lJWH5OXLl2jZsiUYhsH8+fNZz75+/RqBgYGwtLSEo6MjgoODqS53LkxhYSHatm1LdAOXy8X58+dhaGhIcqkBPK/DgIAAajf4MTExaNq0KR4+fAgA2Lp1K2RlZaGrq4uZM2eS5wT1S69evcAwDCtHYWJiIlq0aEHNwRAAhIeHs9bCeXl5MDY2hrKyMssgX1dXh02bNsHT0xPNmzdH165dERgYKDF6cdOmTTh58iRu3ryJHTt2QE1NTWyI5+vXr3H37l1q9SIAYlwqLS1FVFQU1NXVISsrSw4kBY2dw4cPR8uWLcWGdNKmG2NjY3H16lWiB06ePAl9fX2oqKhgx44drGfXrl2L3r17o2nTpujWrZtEyeLhw4ehoaHBCtmdP38+jI2NER8fD4Bn6I6KioKHhwe1erGBv2gwPDXwXb5+/YpGjRrBwcGBnJyOHDkSo0ePRqNGjVg5j/iTz/379xEQEIDg4GCiBLZs2QKGYag6Rb1x4wZ69+7NOjksLy/Hhg0bICUlRQxrQP0TKu1KG+B5dWlqarL6A/Am4r59+yIkJESkHzT269KlS7CwsICvry/OnDkDABgyZAh69+4NW1tbLF26VCSE5P3793BzcyPJPgFg27ZtVC0gAJ5HnYaGhkjCzsjISCgrKyM+Ph6fP3/+7nfQOGbCbNy4EcnJyRg3bhzc3NygpaUFhmFgYmKCbt26oW/fvoiMjGQt7mnl5s2baNu2Ldzc3PDx40eUlZXh3r17mD9/PhiGISfggrrjyZMnCAsLI2P14sULmJqakkqFtGBnZ8c6+X379i3i4+OhoKAg1shbXl6Ou3fv4vXr11RXUxTk5s2bUFJSQrt27aCiogJra2swDIPhw4cjIyMD+fn5ePbsGcrLy1mfo+09i4uLA8MwOHToECorK3H58mUwDIOmTZsiODgYJSUlAP7SiRUVFYiKioKOjg5Wr15NvmfZsmWQl5enaqM/bNgwloGJy+XizJkzMDExga2tLTGcCZ7Yf/36leWVRqscCqchOHToEJSUlFj5F2tqapCbm4uOHTuyctDwP0Ojp8KFCxfg5eUFXV1dPH36FFVVVfjzzz+xbNkyGBkZISwsjDwr+C7NmjWL/P348WN4eHggMzPzl7e/Pj5//gxfX19SIQzgvUvR0dFo3bo1evToIaIrAN6BZVlZmcToxStXrsDMzAza2tpo3rw57O3tSTW7lJQUZGdn4/PnzyIFWWiUxfj4eGhoaJD1YkZGBlRUVNCpUyfMnj2brBcFx2TkyJFgGAYFBQXkWkpKCpo3b06Nbnz37h26d+9O+sUnJiYGKioq6N27t9icpc+ePWNFctAoi8Lz644dO2BgYIC3b9+y7kVGRkJdXZ0UjiguLhZJ59AAnTQYnhqoF8HNe5s2bWBnZ8eabGJiYkSMTwAv4XhxcTFrIrpy5QoOHTr0axr+k7x8+RK6urpYuXIl63pVVRUSExPRqFEjxMbGkuvCoVo0cvPmTbJwnTp1KjlBnDBhAvz8/Fj5FQBg7Nix8PX1/eXt/Kfs3bsXXl5e8Pb2ZiWMHTFiBKytrbF06VLWKX5RURFKS0tZspieno7c3Nxf2u4fUVZWhj59+pAS4IKncBMnToSenh7WrFlDQkNpl0Pg+8ly+ffmz58PbW1t5OfnIyYmBgMHDkTfvn2p29zXx71796ClpQVXV1fi+VRaWoqZM2eCYRiWQWnmzJks134ul4tv377h3bt3v7zd36Ourg79+/dnheECvHcpLi4O0tLSrNwzwuEx/O+gDXFtKikpQUlJCU6cOIF9+/ahUaNG0NLSgrW1NVq0aAFFRUWEhIT8htb+PXr27Al1dXUyx1ZXV6OgoACysrIYNmwYK7wV4G040tPTyXtWVVWFvn37UpN3ka/fEhIS4OLiwrpXV1eHs2fPQktLC15eXuS6ODmkVU/y8/MBvFyFAG9TqKurywqTAXhGX1VVVZHCEbT2DeB54Lm7u0NPTw+PHj0CwAsDjYuLg5GREaZPn06ejYiIYKVs4Pfr1atXv7bRP0FwcDAcHR1Z16qrqxEbGwtzc3OEhoaS9Ye4kDpJ0Iv89hYVFeHRo0fYs2cP1NTU4OLiAkNDQ6ipqUFVVRV9+vT5Hc39Wxw7dgyBgYGwsLBAQUEBysrKcP/+fURFRcHa2hrTpk0TiWyora3FokWLyPg9fvwYzs7OVB1UAjzDi7Ozs0jFzujoaBgbG2PWrFkk5PVHlXRppKCgALW1tdi2bRtUVVWJzuS/X1+/foWioqJIRULa+9VAg+GpgR/AX5i+e/cOGhoa6NatGyuXzoIFC9CkSROsWLECjx8/RkBAAPz8/Mh9Gida4C/llJaWhjZt2uDs2bOs+9XV1UhMTESTJk0QFxf3O5r4t+Byubh79y6UlZWxcOFChISEgGEYsqDbt28fDA0NERoaSq4VFxfD2dkZEydO/J1N/ykET2ays7Ph5uZG8icAPLf9kSNHwtbWFrGxsXj37h2cnJwwaNAgsd9BI5MmTYKRkRHJGyQYijB+/Hjo6+sjMTFRJOyORgTf+8TERIwdOxb+/v5ITU1lVTrLz8+Hvr6+2JNiWnWHsFHs7t27IsansrIyzJo1CwzDYPLkyXBwcIChoaHEGNQuXLgAFRUVkUXdx48fsWjRIsjLy7P0Iu2LPUFZunr1KvlPkIqKCri5uZEE8Pfv38fVq1ep1huCxhZ/f38oKiri4MGDZDN18uRJyMrKYsSIEWSDMnjwYFYoBl8mxRlufjdVVVXQ1tZGZGSkyL2zZ89CQ0MD3t7e5BrtcggABw4cQJ8+ffD06VNMnjwZDMPg/fv3+Pz5M/z9/eHr68sKxf3y5QssLCyoq6IljLC+vnz5Mjw8PNC2bVsSdvf27VssWrQIHTp0gI+PD7y9vaGpqcnSizSOIb9NN27cgJOTk8hYVFVVkeT9U6ZMIZtjGvsiiOCYFRQU4MSJEzh9+jTrmW/fvqFLly5YvXo1uFwuiouLcf78eYmZy86cOYPevXvDzMyMFDL5+vUrZs6cia5du2LGjBmkL2FhYaxcm/zfhyYjKF+m8vPz4ezsTCrgCo4Hv5DQ7Nmz8eHDh9/Szr/Lvn37iDEzNDQUDg4OKC8vR01NDYyNjUUMvg8fPkT79u1x/vz539DaBv4TGgxPDfwQfojP27dvSXU3QeNTfHw8GIZBp06dYGxsTOUCtj4eP36MwMBA9OvXj9UngGd8Sk5OBsMwIqeQtLJ69WooKCigadOm5CSVT3p6OkxNTdGpUyc4ODigS5cu6Ny5M/VJIcWxa9cueHh4wMfHhywmKisrMW7cOHTu3Blt2rSBpaUl1YmA+Qj+7kZGRnBzcyN/CxqfJk6cSF3Oix8xffp0qKqqIi4uDuPHj4eBgQH69u1LxuXu3bto2rQpa/HA5XIlQhYvXbpEDE337t1DmzZt4OLiQhZ6NTU1SElJgZOTE4YOHSoxORW4XC7Ky8sxatQo9OvXT8RLsqioCIsWLYKSkhIrZwutCMrSrFmz0KFDBxgZGUFBQQFhYWGsTUWfPn0wZMgQkc/ROGbiDLM9evSAiooKDh48SN6xU6dOQVZWFtbW1rC0tESHDh0kYo7m/+YpKSmwtrYWyVsC8KpraWtro0uXLr+6ef8YvsHMyMhIpCjG7du3YW1tDScnJ4SFhWH79u1wcXGBiYkJlTIojuPHj5N/841POjo6xPj0/v17bN26Fb1795YovQj85Zns6elJvP/5eqKyshLR0dGws7PD8OHDRTxpaENQv82YMQOdOnWCrq4urK2t4ezszNIvU6ZMESlyAtA7ZsK68cSJE8T4xA9PKykpwaxZs9ClSxd4enrC09MTampqrIMG2tchAQEBsLKyIp7wgnp99uzZsLKywsSJE6mvVF1TU4OMjAyoqanBxMQE8vLyuH//Prl/5swZ6Ovrw8rKCrm5uTh48CB8fX3RpUsXamWwgfppMDw18F1SUlIQHh5Okv/WZ3wqKCjAsWPHJCbhtiCZmZmwtbXFqFGjWC7fAG8xkZ2dTXV/BEMAc3NzoaSkBDU1NSxcuBAvXrxgPXvhwgVs2rQJ48aNw9KlSyUmKTXA85wZNmwY+Vuc8am6uhrnzp3Dvn37JEoW+Quls2fPQlNTEz179iT3BBc/CQkJEjPRnjlzBu3btye5Eg4cOICmTZsSIy6/X23btqUq99uP4HK5OH36NBiGwbJly4gHmjjjE8Cu4icJsshn//79MDU1FVu+vaioCLNmzZKoZJ7x8fFQUVEhRs6IiAgwDIOrV6+SdyoiIgLOzs6/s5l/m3379rEKLogzPt27dw/jxo3D7Nmzqa4SKY5Hjx6hb9++8Pb2Jqf7gpw4cQIBAQHUekjyETSojxo1Co0bN4aXlxcr/BbgjdXUqVNhZGSErl27omfPnhJjnLl9+zYYhsGUKVPINXHGJ+GxkgS9yB+7169fQ1VVFf369RPZ0FdWViIsLAzBwcHUyyOfZcuWQVlZGRcvXkRdXR1iY2PBMAxOnjxJnlm6dCkMDAyolz9h9u/fT/594sQJ9OnTh2V8Ki0tRUpKCoYOHYohQ4ZIzHvGl63i4mLo6enBy8tLbH6jSZMmYfjw4RIzR/v7+4NhGJYXK8DTD3/++SdcXFzQpk0bGBoawsPDQ2LGqwE2DYanBr7L9OnT0a5dO0RHR5MS4XzjEz/huLBSo1EJ/CjGecOGDXBwcICHhwcOHDjAeo5mA4bg4ubGjRvk2sqVK6GpqYl58+aJJKwG6D/NF6ayshKLFy+GlpYWJk2aRK7zjU++vr5iXW4loW+CfPv2DXv37oWWlhZsbGxw584dsWFoNPZLeKGdnZ0NMzMzALwS6HJyciQfXFlZGXJzc1FdXY158+ZR+W79iBkzZkBFRQUrVqwg+Qfu3bsHbW1tuLu7s5IEA/SfnoojJSUFOjo6mDRpEi5dusS69+nTJ4lJ5snlctG/f38if1lZWVBUVERSUhIAEO+EtWvXEmMa7X0CeEaZ1q1bY9CgQayKYILGJ37Yj6DOkLT37dKlS3Bzc4OHhwfWrVvHuifYL1o3+4Lt4nK52LVrFzZv3gx9fX0MGDCAhH0Kvk+1tbUoKiqiOhGwOLZt24bmzZuzkohfvnwZnp6e0NfXZ3kyAPTrDkH4snblyhXIy8ujZ8+euHHjBqsP1dXVZLxplUc+3759w9ChQ0ll4z179rAqHfMPTTIyMtCjRw+JGqs7d+6AYRjiwQqINz4Jr6Uk5T3jy9alS5egqakJV1dXPHnyRKT9/P7ROHaC70dxcTHWr1+P+Ph4tG3bFv379yf3BMfo5cuXePHiBdWVFBv4Pg2GpwYI9U2S8+fPR8eOHTFv3jyW8YlveRY+DacNwX7x2y/u3uHDhzF+/HjIyMhg5syZVFVUEYfgRDJ79mzo6+uzQgKXLFkCTU1NxMTEEM8nf39/UkaWZsTJ4qdPn7BmzRro6upiwoQJ5Pru3bvh7e2Nrl27ioQF0cbPTP61tbW4f/8+7O3tYWlpiQkTJuDChQsSER4DgBgoDh48CE9PT2RnZ0NOTo5s8gFeBaeQkBBWRUkajWnA95PDzpo1CwoKClixYgXxfLp//z6kpKRYBlJaqe83FzbKOzo6wsHBARs2bPjus7RSUlICHR0dHDp0COfOnYOsrCwxQlVXVyM8PBxXrlzBx48fRaqN0YS4Nu3fvx8mJiYICgpCfn4+ue7v7w91dXXs3r2b+sX5z2zQCwsLERISAgMDAwQFBeHFixcoKyv7Ba37zxDs2+LFixESEkLy+OXl5UFXVxcDBgxglQsXziFEoyx+j4yMDEhLS7MqYF65cgWWlpYSkZRaWB6FDYcAz7tLX18f7u7uiIuL++5naEFYjrhcLmxtbbFu3TocPnwYsrKyZJ6ura3F0qVLkZOTg9raWokxpvGprKxERkYG5OXlMXz4cHL9xIkTCAwMhKWlJSuXGkDne/Yz66KbN2+ic+fOMDc3x+rVq1l5NAE6x0ywTSkpKUhJScGLFy/A5XKRkZGBNm3aYMCAAazPnDp1ipU+g8Z+NfBjGgxPDYhQWFgo4kIcHR2Njh07Yu7cucSD5tWrV/D396d2wyjMjBkzEBgYyKooA7Anm5qaGhw7dgyDBw+GnZ0d5syZ88My9r+befPmQUVFBadOnRIJrVu6dCnatm0Lf39/2NnZoXXr1hJjwADAOsUHePnGVq1aBV1dXdbGfuvWrQgNDaV6IhLsy8KFC8mp4vdYv349JkyYAC0tLaxdu5aqJJd8srKyEBoaCuCvpJAVFRUoKSmBpqYmGIZh9bWyshLe3t4YOHAglQu9+liyZAm2bNkikrtj5syZkJGRwYoVK8iC7/nz59TrRf7mF4CIFwLAXtRdvHgRCxcuhKKiInr37o3w8HBW9Uia+PPPP8k4REdHo7CwEACvCpCtrS2aNm1KqkcCvLBBZ2dnrFq1ilyjXS6F5+cDBw6gU6dOCAoKYpV7t7e3h4+Pzy9u3T8nPj4e27dvr/d+UVERzpw5AysrK7i5uaFbt264ffs29e8aAEybNg0aGhpYvnw5Hjx4QK7z85cEBgYiPT0dfn5+UFFRkYgqugAQGxuLxYsXi1zPyMhAkyZNMGvWLHLt7t27VM/RADs0+tSpU2KfEaz4PHv2bDg6OqJ9+/aIjY1lVdulicLCQnI4EhERQd6ziIgIuLi4oGXLlqwK1W/fvoWPjw+r6rMkyKMgVVVV2L59O1q0aMEyPp08eRLOzs4YOnTo72vc3yQ5OfmHFXDDwsLg7+8PLS0tLF26FNevX/9FrfvnhIeHQ0VFBRs3biTr24qKCmzfvh3a2tro1asXXr58CQ8PD/Ts2VPiZLABURoMTw2wOHToEBQVFZGYmMjamAA8w02LFi0QFRVFSuTyoXHhJ6ig8vLyYGFhIRIuUt9nqqurUVVVJZJ/gTbevHmDrl27iiReFTQupaWlITQ0FGPHjpWonE6nTp2Cqqoqq3Q7wKusFR0dDVlZWcyePVvkczQubF+9egUZGRkEBQVh6tSpkJWV/e4CVfh9unfvHt6+ffvfbubfhsvlYvPmzWAYBra2tpCTkyMhnwCv8kqrVq3Qs2dP7N69G5mZmXB3d0fnzp3FlpummT59+kBGRgZZWVkixqeePXtCS0sLCxcuZJU3plEvAsCRI0cwbtw4lJaWYvz48Wjbti1rw8VHeGxevXqF9PR0zJ8/n4Qq0MT169dhZGSEqKgojB07FgzDkFyEOTk5MDExgbOzM/G0Kyoqgre3N+zt7akdK2FWrVqF4OBgkTl4//79UFdXR79+/VjGJxr1IR/BtqWlpUFDQwOXL1/+qc/evn0b27Ztk4iqRkePHoWmpqZI9Vx+/8+fP088XJ2dnSWm4EdNTQ2ioqLAMAzWrFlDrnO5XNTV1WHUqFFgGEakci6tMpmVlYUBAwbg27dvCA0NhYqKSr1Vwfj6gm8gXLduHdLS0uo1Vv1Onjx5AoZhEBERgZCQEMjJyRG9eOXKFbRu3RpdunTB3bt3AfDyWPn4+MDW1lZi9CLAy4Ep6GUH/GV8kpaWxvjx48n1K1euUCuHAPsdWb16NRiGqdeQJDhGZWVl2Lp1K5KTk1nzAI3s3LkTmpqaYqMwysvLsXfvXmhra6Nt27awtraWGL3YwPdpMDz9jyPuBR4xYgQ6dOiA5ORk1iaquLgYrVu3hoqKCtavX1/v52kjLS0NY8eORXBwMAB6Fz3/hDt37qBZs2YiLsMAWLmBBA1RkmB0AngVByMiItCpUycsWrSIde/69etQUVEBwzCIj4//TS38e+Tn50NKSgpycnJkgSdJizpBQkJCiCcJADg7O4NhGFbyd/7m4+LFizA3N0e7du1gbW2N/v37U58Usj4dMWzYMMjKyiIzM5NlfJo4cSIMDAzg7e0tEToxISEBxsbGsLS0hLKysliPJ2FoHSsAJIE9wPNyUldXR7NmzVgJcgHeAt7a2hra2tpko29paUm9PAqSlJQENTU1hIeHixif4uPjIS8vj4CAAJYBmPY578KFCwgNDSX5m773DknCGAmTmpqKrl27iq2Yxe/P27dvqc9dIk6OysvLsWTJEjAMw/IaBHjvoqenp0iVNFo5f/48GIaBsbExFBQUyDskCTpdHJcuXSK6LTc3F9LS0mjWrBlOnz4N4K/xzMvLg7q6OiwsLNCuXTvY2dnByspKovRiZWUlFixYgBYtWiA6Opp1r6qqCiNGjADDMCLhW7TL5enTp5GYmIicnJzvPicujJJ2YmJi4OHhgaqqqnrzRX79+hV5eXlU68UG/h4Nhqf/YQQVrvDLPHLkSOjr6yM5OZl4Pt2/fx8TJkzAqlWrJGIi4jNgwAAwDANLS0tiSJMEpSyMuDa/evUKJiYmWLVqFVkk8Mc1MzNTYowywpM/v69Pnz5FZGQkOnTowDI+PXr0CEFBQdizZw/VsijYr0uXLkFKSgotWrRgGWjq6zutVFZWwsjICHp6erh58yYAXu6S6OhoyMjIsJLK8vVKdXU1Pnz4gA8fPlCfLFdwPC5cuIDCwkJWiGNQUBBkZWWxc+dO4vo+YMAAFBYWUp9sW7BvAQEBYBgGgwYNqvdUXxy09S0+Ph5GRkbIysoCAOzduxetWrVChw4dEBUVJZLk/eLFi0hJSUFUVBTS09MlpniEIBs2bICmpiamTJlCKoUBwJo1a+Dq6ophw4ZRv6ECeLJUWFgIGRkZSEtLY9myZb+7Sf8VkpOToaury8ppx+VyUVNTg61bt5IQKD40jp1w6O3Ro0dJvhUul4tFixaBYRisXLkS5eXlqKioQGBgIHbt2kU+R5vu4MNP5g4A/fv3B8Mw8PPzYx28Shpz5syBjo4OsrOzUVlZifz8fDRt2pR4PvHnLv6Y3L17F7t27cLChQuxd+9eqvUiIP4def/+PZYvXw55eXnMmzePdS8uLg5+fn7w9vam8v0SR0FBARo1agQZGRlieJKUtn8PvmwFBQXByclJ5HptbS1OnDghkpOX5rV+Az9Pg+GpASxduhS+vr6YNGkSy6o+atQodOzYEZMnT0ZWVhZ8fHzqrTRAC/UtbPhu08uWLZPIxYTgZFNeXs5KHjh48GDo6enh+PHj5FpVVRV69OiBAQMGULvYE8fSpUsxYsQIDB48mOSrevHiBWbOnAk9PT2MGzcOJ0+ehIeHBytHEI2yKEhOTg7evn2Ld+/e4fTp01BQUMAff/zxu5v1tykpKQHAy4Ph7OyMtm3bsjwr0tPTIS0tjalTp7I+Jxx+IAkyGR4eDg0NDTRr1gwBAQFIT08n94YPH45WrVrB0tISpqam6NixIyv0gnYqKysRGxuLyMhIWFlZYcKECXj8+DEAyWi/IMePH0dgYCCcnZ1x8OBBVFVVkXBcc3NzREZG/jBMlUb9IfiO5OTkICMjg/UerV27FpqamggNDcXZs2dRWVmJXr16sXIkScpYbtmyBUpKSvDz8yPeoJJIfb/36dOnoaqqihUrVrByRlZWVqJ79+4SZXCbNm0aVFVVIS8vj06dOmHPnj3E+3P58uVo3LgxOnfujPbt28PExESiQqqrqqqwZcsWbNq0CTIyMhg8eLDYqsAA/e9WcXExXFxcYGNjw6rUfODAATAMgylTpuD9+/ff/Q4a9SIgejh0/Phx4uH/9etXJCQkQEFBgRifSkpK0L9/fxKpIfwdtPL27VskJCRAUVGRldNUEtouSH3t3bNnD6SlpVlrKwB49+4dAgMDcfDgwV/RvAZ+MQ2Gp/9xli5dClVVVYwbNw52dnYwNzfHihUryP25c+fCxsYGurq6cHV1pTrGVlC5PX36FC9evGCddo8YMQLt2rVDSkqKSP4qmhHsV2xsLNzc3NCqVSsMHz4ceXl5AHihTh07dsTgwYMREREBe3t7icujExcXBxUVFQwdOhQmJiZQUVEhLuGvX79GUlIS1NXVYWhoiO7du1Mti3y4XC4KCgogIyNDTrvr6upw6NAhKCgosJJbjhs3Dlu3bv1NLf0xvXr1wvjx40ly/tLSUjg6OrKMT7W1tdiyZQuaNm2KCRMm4MmTJ/Dx8UFAQADV4wSw5ejSpUswNTVFQUEBDhw4gL59+8Le3h4pKSnkmXXr1iEmJgazZs0i7xmtC3VB4uLiMGPGDPL3ihUrYG5uTsaLj2AoJY2sXLmSjNnZs2fRu3dvdOvWDdnZ2eSZWbNmwdzcHHPmzCEn/MOGDSOeepLA9OnToaKigtatW8PMzIxV0TMtLQ3m5uZo1aoV2rVrR73OF5zLhN+V9evXo3Xr1ggLCyNGUElCsG+bN2/GggULMGbMGJKXJTo6GvLy8pg7dy6OHTuG8+fPw8PDAxYWFtR6lQBsObpy5QosLCxw+vRpPHnyBD169ICRkRG2bNmCyspKAMC5c+cQExODhIQEidKLq1atwogRI8jfZ8+ehbS0NAYPHszyVPtRyNPvZu3atUTmSkpK4OTkBAsLC5aBMDMzEwzDIDw8nBjl+/XrR33fhJk+fToUFBTQqlUraGpq4vDhwwB4/V69ejVkZGSgr68PAwMDGBsbS4xuFOTTp0+Ij4+HtLQ0oqKifvg8bQi2c//+/VizZg1SU1NJeP/o0aPRtm1bJCcn4+PHj7h16xZ8fX1haWkpEXqjgb9Pg+HpfwxhZTV79mwcOXIEAC+UburUqejQoQOWL19Onnnz5g2eP39OdYyt4EQye/ZsmJubQ1FREfb29ixlPXz4cLRv3x5r164VqQxEO3PmzIG6ujo2bdqEgoICtGnTBl27diUeXDExMejTpw+8vLwwadIk6hd9wrI4c+ZM4rVVUVGB/v37Q1FRkXXK/+XLF9y7d08iZJH//9LSUujp6eHcuXOsZ/jGJysrK9jZ2aFdu3ZU9odPcnIyGIbBzJkzWcYnJycnEePTrl270Lx5c3Ts2BHm5ubUGwmFZfHKlSsYOXIk+fvOnTsYMmQI7OzskJqaKvY7aB47PnV1dQgODsaYMWNY11esWAFLS0sEBwcjLy8PHh4esLS0/E2t/DG5ubnQ0NDAkCFDyDW+8cnR0ZGE3QG8+cDS0hKenp5wdHSEqqoq1WPFl0Uul4s3b97Azc0NN2/exPPnz7FkyRKYmZmxDNYFBQXIzs7Ghg0bWKEKtCH4jiUlJWHIkCEICgpiFY9ITk6GhoYGwsLCWEZQSWLatGlo1aoVxowZAzc3N2hqaiIhIQEA7+DIxsYGTZo0gbm5OVxcXKjOoyOcjuHRo0eYNm0a65m+ffsS45O4AgU0v2uCjBw5Eh4eHgD+6ve5c+fQtGlTDBw4EIcOHUKPHj1gaGhI7Tx2+PBhaGpqYvz48bh9+zaAv4xP1tbWyM7OJuGRmZmZkJKSgo+PDywtLdG+fXvqKx4L/u6FhYUwNzfHqVOncP/+ffzxxx8k/yKfmzdvIjo6GqtWraJ6PSxstJ43bx5Gjx6NS5cuoby8HNXV1SR/n2D+KlrlUBzTpk2Drq4uHBwc4O/vDykpKRQWFuLJkyeYO3cumjVrhlatWsHAwAD29vZU68UG/jMaDE//Qwgqt9zcXJw+fRoeHh6sBKyPHj3C1KlT0bFjR5FEkcLfQSMLFiyAkpIS9u3bhx07diA6OhrNmzfH5MmTyTPBwcGQk5PDnj17fl9D/wZcLhePHj2Cqakpjh49CgAkXn/Dhg0iz0tCInFBOcrLy8OBAwfQq1cvlnGmpqYGAwYMgJKSEvF8qu87aERwEa6vry/2fbpz5w5GjRqFiIgIqhdG/AVOeno6GIZBZGTkd41PAC//2KlTp6g2EgoTFxcHNzc3eHh4oF+/fqx7d+7cwdChQ9G9e3dWiWmaEfeOLF++HMbGxigrKyObEIBnDLCzs4OOjg7s7e1Z92ijtLQUSUlJsLCwQFBQELl+9uxZ9OnTR8T4lJSUhEmTJmHEiBFUv2eC41VUVIS7d+/C19eXHC7wT/JNTU1Z5cEFobFfgkREREBFRQWTJ09Gjx490L59e3Tt2pXcT01Nhba2NkaNGsXyNJEEcnJy0KZNG+JxcvLkSTAMg507d5JnPn/+jJs3b+Lhw4cSoxvnz58PFxcXaGlpwcvLS0TG+vXrB2NjY6SkpIhU/KQRcXoxIyMDtra2qKysRF1dHRmT/Px86OjowNzcHLa2ttQfoiQnJ8PS0hJjx479ofEpNzcXkyZNwtSpU6mveCw4Zt++fcP9+/dF8jgNHToUsrKyyMrKQkVFhch30No3PmFhYVBRUUGPHj1gZmYGdXV1zJs3Dx8+fEBFRQWWLl0KZWVlkcp9tLNlyxa0atWKVBXftGkTGIZBRkYGeebhw4c4dOgQzp8/LzF6sYF/RoPh6X8EwUkyLCwMLVq0gKamJmRkZESU9+PHjxEeHg4FBQVWYkjaKSkpgYeHBxITE8m18vJypKeno2XLlli7di25vmjRIqoX6MILo8ePH8PU1BQAkJ2dDVlZWSQnJwPglU/Nyspi5X0C6F0YCTJt2jQ0b94cHTp0AMMwWLZsGWvBUFtbiz/++AMMw+DatWu/r6F/k4SEBHTs2BFBQUGYOHEifH19ERERgadPn373czROtMKymJaWVq/xSVdXV2wYE63vmmDfli1bBnl5eUyaNAk2NjZo2rQpli5dynr+7t276NGjB8aMGSMR7xefnJwc5Ofno6ioCKtWrYKNjY1YWXv48CGuXbtG9cKP37by8nIkJibCzMysXuNTffMXjf0SZPbs2dDX10fXrl3RuXNn1r3S0lKsWbMGFhYW6NWr129q4T+jsLAQbdu2JVVYuVwuzp8/D0NDQ1aS2ZUrV0pceC7AC3MKCAgAAGzbtg0tW7ZEUlISAF7Onfv374voUxoPUAT7tWHDBrRs2RILFixA9+7d0bp1a8TGxop4N7m6ukpc3sJNmzbh5MmTuHnzJnbs2AE1NTWxYZ6vX7/G3bt3qdaLgm1as2YNzM3Nf8r4JHjAQGO/ALY8xsTEwNPTE+rq6vDy8mLlTAN4odQKCgpIT0+n+vBEmMOHD0NDQ4O1zp0/fz6MjY1JkaD3798jKioKHh4e1OtG4K9xmzdvHkJDQwEAu3fvhqysLNmPlZSUsIq38KF1zdjAf06D4el/AEEF9eLFC1hZWaGwsBAXL17E7Nmz0axZM5EN1v3797F69WqJevm/fPkCTU1NzJkzh3W9tLQUffv2RUhIiEh/aO8fPw762bNn0NDQIAZB/mIWAK5evQp3d3fk5+f/rmb+NMKeTvb29jh58iTu3buH4cOHQ1ZWFrt27WKdmtbU1GDevHnUj5UgGzduRHJyMsaNGwc3NzdoaWmBYRiYmJigW7du6Nu3LyIjI8nJuCRw48YNctq7ceNGscYnFxcXNGvWTCJytAjK4tmzZ5GYmEhyRDx79gzh4eHo2LEjK+yYf08wHIp2bt68CSUlJbRr1w4qKiqwtrYGwzAYPnw4MjIykJ+fj2fPnpHkrHxofN/ElVpes2aNWOMTP+H4tm3bfnUz/zaCsrht2zaoq6sjJSUFEydOhJKSEnr06MF6vrS0FIsWLcLQoUOpNFzwEX5PDh06BCUlJVbuxZqaGuTm5qJjx47Eo1fwMzT3T5ioqCgEBATg4sWLkJOTYx2CpaWlITIyUmw4Gq0cO3YMYWFhrLxpY8eOhbW1NRYvXoyysjLW85I0VleuXIGZmRm0tbXRvHlz2Nvbk2p2KSkpyM7OxufPn/H8+XPW52jso7h5aNWqVWKNT87OzrC1tUVGRgaVOl4Ywd973bp1UFBQwNy5c+Hp6QlZWVmRhP0A4O/vDzc3t1/d1L+F8G+/Y8cOGBgY4O3bt6x7kZGRUFdXJ16vxcXFVFfPFdemadOmYcKECcjJyWEdmnO5XGzcuBFz584V66HWwL+TBsPTvxh+DiO+4l64cCF69+6N4OBgcrLx/v17LFiwAC1bthQxPvGhcXK6efMmWbxOnToVFy5cAABMmDABfn5+ZKLlM3bsWPj6+v7ydv4nHD9+HAzDEONTdHQ0mjVrxsrPUlVVBT8/P/j4+FC5IOIj7AWzfv16hISEYPz48azrQ4cOhZycHLKyssS67NN4Ive9hLn8e/Pnz4e2tjby8/MRExODgQMHom/fvlS+W+LYuXMnDA0NsWnTJjIG4oxPJSUlmDBhAtX9mjp1KkmEC/Cq4jAMg5YtWxJPDAB48uQJMT6JC62j9X0T166SkhKUlJTgxIkT2LdvHxo1agQtLS1YW1ujRYsWUFRUREhIyG9o7T8jLi6OGAnrMz6dO3cOzs7OIjqGZnbt2oWNGzeSKj8VFRXIysqCjo6OiHdTRUUF1cYZvk4AeAYMgGe01dXVxebNm1nPvn37Fqqqqti0aRPrOo0bK2EWLFiAiIgIADyPwdatW4NhGFYfKysr4evri9GjR1Pbp/DwcNZBSF5eHoyNjaGmpkbygAK8MCe+8WnJkiUihjQaZREQbRd/HIqKivDo0SPs2bMHampqcHFxgaGhIdTU1KCqqoo+ffr8jub+I9avX8+KYKjP+NS5c2eMGjXqN7Xyn5Gfn4+xY8eyUmSMHz8e+vr6WL16tUjOVlrlUJiCggLU1tZi27ZtUFVVJXqTb4j5+vUrFBUVsW/fPtbnaNUjfDZt2kQKVaWlpaFjx46QlZXF6tWryTNfv36Ft7c3IiMjf1czG/gNNBie/qVER0eTRIkAb0O8bNkyNG3aFFZWVqxn379/j9jYWCgqKoqE3dEGl8vF3bt3oaysjIULFyIkJAQMw+DPP/8EAOzbtw+GhoYIDQ0l14qLi+Hs7IyJEyf+zqb/bT5+/AgXFxfExcUBAG7duoXhw4dDXl4e4eHhCA8Ph6urKzp16kQ8UWicbJOSkkgVLb5BYsiQIWAYBra2tiILBkFXadqTXQr+3omJiRg7diz8/f2RmprKCn3Mz8+Hvr6+iFeJ8HfQyqdPn+Dl5YXu3bsjPT1dxPg0a9YskdLMtBqf7OzsiNEC4G16Fy9ejJYtW2LWrFmsZ588eYKIiAgoKCiw8rTQiqAsXb16lfwnSEVFBdzc3Eh/7t+/j6tXr1Jp1BVHaWkpAgMDwTAMKTwgaHwSTDj+559/Uvt+DR06FJcvXyZ/v3z5Ei1btgTDMCwvu4qKCuzatQu6urpiN8E0bkAOHDiAPn364OnTp5g8eTIYhsH79+/x+fNn+Pv7w9fXl2Xk/fLlCywsLCTiHRNm5cqVMDQ0xN27d1FTU4OVK1dCR0cHU6ZMwbNnz3D69Gl4e3vDxMSE2qpanz9/hq+vLy5evEiuVVRUICYmBpqamujbty9r7qqtrcWECRPQtm1bqiux8hHUAQUFBThx4oRI3shv376hS5cuWL16NbhcLoqLi3H+/Hlq5zFhiouLMWrUKBgbG2PJkiXkOt/4NG7cOGJ8Ki8vp7pfsbGxuHr1KnlPTp48CX19faiqqopU3uMbnxITE/Hp0yfWPRp1/759+4geDw0NhYODA8rLy1FTUwNjY2M4Ojqynn/48CHat2+P8+fP/4bW/jMqKyvh7e3N8tTt27cvWrZsiczMTDx+/Bi3b9+Gl5cXLC0tJWbt0cD/DQ2Gp38pN27cQO/evVnJOcvLy7F+/Xo0adIEMTExrOc/fPiAGTNmwN3dnbpFkThWr14NBQUFNG3alJym8klPT4epqSk6deoEBwcHdOnSBZ07d6Y6KWR9E2RoaChMTEzI3w8ePMDq1athaWmJPn36ICwsjPqkkJmZmdDQ0MDLly9Z12fMmAF1dXWJdZUWZPr06VBVVUVcXBzGjx8PAwMD9O3bl+QYuHv3Lpo2bcpaPHC5XOpk8ePHj/W26cuXL/D19YWdnR3L+MRPFJmSkvIrm/qPqKurQ//+/VnFBgDeqXdcXByaN29ODL18Hj58iMTERKoX6gBbr82aNQsdOnSAkZERFBQUEBYWxsqj0KdPH2KgEfwcjX3kt0mwna9evcLIkSPRpEkTYsD4+vUrEhMTYWlpCT8/P9Z30LgBGTZsGObPn0/+5nK5OHPmDDp37gwHBwfWWFRWVmL37t1o1qyZRJwOnz17FhoaGjAyMoKSkhJu3bpF7t2+fRvW1tZwcnJCWFgYtm/fDhcXF5iYmFApfz/i6tWrMDExIV5qL1++xJo1a9CmTRsoKSnB1NQUvr6+1FdpCg4OFtn0VldXY8GCBejSpQumTJnCCoepqanB0qVLqe0PH0G9MWPGDHTq1Am6urqwtraGs7MzSzdMmTIFI0aMEPkO2vvI5+nTp5g6dSrMzc2xePFicn316tWwsrLCoEGDWHkmaezXu3fv0L17d5w5c4Z1PSYmBurq6ggKCsK7d+9Y9yZOnIgWLVpg9+7dv7Kpf5uamhpkZGRATU0NJiYmkJeXJxENAHDmzBno6+vDysoKubm5OHjwIHx9fdGlSxcqx0oc/Pft+vXrkJWVZYW6+/j4oHPnzpCSkoKNjQ0cHByo14sN/N/TYHj6l/Ly5Uvo6uqKhIhUV1cjMTERjRo1QmxsLOvely9fqI4drqurI+3Kzc2FkpIS1NTUsHDhQrx48YL17IULD/5EIAAA2eBJREFUF7Bp0yaMGzcOS5cupd44w+fFixesELOysjK0adNGxBND2BOIZqVdVlaGPn36IC0tDQC77RMmTICenp5Eu0qfOXMG7du3R0FBAQDeaX/Tpk1JqAVfZtu2bcvKlUEbxsbGrE3tli1bcOjQIdYznz9/ho+PD0xMTLB9+3byPh08eJD6d4vPhQsXoKKiIuK6XlRUhEWLFkFeXl7E+MSH5veMT3x8PFRUVIiRMyIiAgzD4OrVq6T9ERERcHZ2/p3N/CHh4eF48OAB+fvDhw8A/nqfXr9+jeHDh0NKSopUZi0uLsbixYsxbNgwavUHv/0JCQlwcXERuXf27FloamrCy8uLda+iogKnTp2iWgYFjemjRo1C48aN4eXlhXv37rGeu3fvHqZOnQojIyN07doVPXv2pH4DIrgmEk5aPGXKFGhpaZEDFC6Xi4qKCly+fBnPnz+nOik1v183btyAk5OTiNdZZWUloqKi0LVrVxHjEx9ax0yQZcuWQVlZGRcvXkRdXR1iY2PBMAyrqvPSpUthYGBAdX9mzZrFSkAtnMbg2bNnCA0Nhbm5OcvzKS4ujmq9KEhkZCScnZ1JXiM+UVFRMDMzw+zZs0U8rBMSEqgeN0H8/f3BMAy8vb1Z12tqavDnn3/CxcUFbdq0gaGhITw8PKjWjeL2ilwuF5WVlRg5ciRGjBiB4uJicu/mzZs4dOgQbty4QbVebOC/R4Ph6V8IXxGkpaWhTZs2OHv2LOs+3/jUpEkTsRssWo1OfPgl2+vq6rBy5Upoampi3rx5Ih41AP2n+YJs3LgRurq6CAoKwv3790l758+fDy8vL7x79w5cLhd1dXUSsXgQZNKkSTAyMiITkGCOHUlzlRZuU3Z2NszMzAAAWVlZkJOTY1UczM3NRXV1NebNm0ftBBsdHQ0TExPSt2/fvsHAwAAODg6skBiAtwHW0dGBra0tkpOTWe8Vrf3jw+VyUV5ejlGjRqFfv34iueD4xiclJSXMnDnzN7Xyn8PlctG/f38if1lZWVBUVCTFCPhG7bVr15LKODTqe3d3d9jb2xN5ysnJgbS0NAmf5rf51atX6Nu3L2RkZEhxhbKyMqpzH/GpqqqCtra2WA8mvseQ8MaED41zmeBvzeVysWvXLmzevBn6+voYMGAACfkUPNyqra1FUVERuUa7/gB4BoyZM2eyvFdfvXqFrl27kjAtcSHiNMsi8NcBkaenJ0mozR+XyspKREdHw87ODsOHDxebf5Fmvn37hqFDh5JKWnv27GFVOubnqcrIyECPHj2o1IkA4OnpiU6dOpH27dmzB0ZGRsTbjs+TJ08wePBgtG3blpXgnna9yG9ffn4+nJ2dcfDgQQBsfTdr1iyYm5tj9uzZ5DBCENp1Y3FxMdavX4/4+Hi0bdsW/fv3J/cE2/7y5Uu8ePFCYowzq1atQmJiIsvItGXLFsjJyYmE+wtCqyw28N+jwfD0L+bx48cIDAxEv379WK7uAM/4lJycLJIEk0YEFwH8MtOCbV6yZAk0NTURExNDPJ/8/f1x5cqVX97W/4Tq6mosX74cPXv2hKysLCZNmoRTp07hxYsXkJWVlcj8F4JjZ2RkxAqfEzQ+SYqrtCCXLl0CwPP28fT0RHZ2NuTk5FgVBw8dOoSQkBBWyCuNC6OpU6fCwsICABAWFoaMjAy8evUKXbp0gaurK44fP856PiAgAKqqqpg4cSK1i/TvsX//fpiamiIsLAxPnjxh3SsqKsKsWbMkpmSxICUlJdDR0cGhQ4dw7tw5VgWZ6upqhIeH48qVK/j48SO1lfnu378PIyMj4omQn5+PEydOoEePHtDW1mYdPAC88swMw4BhGPJOAvT1SxC+DkhJSYG1tTV27Ngh8sy5c+egra2NLl26/Orm/W0ENw+LFy9GSEgI2YDk5eVBV1cXAwYMYHlqCM9nNI+XIBEREfD09IS8vDymT59OcgWNHTtWxINNUhD0IlRVVUW/fv1EPJArKysRFhaG4OBg6jeLwrLE5XJha2uLdevW4fDhw5CVlSXzdG1tLZYuXYqcnBzU1taSvtHWx4cPH8LCwoIYPC9cuIDCwkL069cPjo6O2LJlC+v506dPo2XLllBTU2OtlyXlPQsICICVlRWRQ0Fj7uzZs2FlZYWJEyeKyCltCMpRSkoKUlJS8OLFC3C5XGRkZKBNmzYYMGAA6zOnTp1ieVXSJovClJeXIzQ0FDIyMvDz88Ps2bPJvaFDh8Lb21tsftMG/jdpMDz9y8nMzIStrS1GjRpFTov5VFZWIjs7m3pLOp958+ZBRUWFGGMEWbp0Kdq2bQt/f3/Y2dmhdevW1CemFkR4DNLS0kgyPr5RwMjICG/fvv1NLfzn8CdNfghJz549yT3BRRDtrtJZWVkIDQ0F8FdSyIqKCpSUlEBTUxMMw5ATVOCvBIsDBw6kdrHHb9fZs2dhaGgIExMTtGzZkoTGPH/+HBYWFnB1dSWlzrlcLkaNGoW8vDxqjRc/Q0pKCnR0dDBp0iSWwQLgJVOnOewY4CXO5iewj46ORmFhIQBemIKtrS2aNm1KwlsBnkHN2dkZq1atItdo7NuDBw/Qvn17xMbGYsiQITAzM8OXL19w48YN9OzZExoaGqy5LD8/H6NHj8aqVaskZi7j8+jRI/Tt2xfe3t7kdF+QEydOICAggPqNB59p06ZBQ0MDy5cvZ4VJ8nOXBAYGIj09HX5+flBRUWGFz0sSnz59QlZWFiwtLWFqaophw4bh6NGjaNKkCdavX/+7m/eP4M+9V65cgby8PHr27IkbN26IhBjSapjhU1hYSDynIyIisH37dvJvFxcXtGzZkhjjAV5xCR8fH1ZaChpl8suXL9DQ0MCwYcMwYcIESEtLo7a2Fn/++ScGDhwIe3t7lvHp4sWL6NevH1JTU6leVwnDl6vi4mLo6enBy8tL7Fw8adIkDB8+nMqxEkd4eDhUVFSwceNGkm+xoqIC27dvh7a2Nnr16oWXL1/Cw8MDPXv2lJh+CfLw4UNERkaiY8eO0NfXx7JlyzBr1iz4+/uLhIQ28L9Lg+HpX0B9MbZ8NmzYAAcHB3h4eODAgQOs5/gTEu0L9jdv3qBr164iJ8OCxqW0tDSEhoZi7Nix1OZ0ErdRr2/x/fXrV5w7dw6urq5QVlZGt27dJHIy4vPt2zfs3bsXWlpasLGxwZ07d8SegtC4SOJyudi8eTOpxCcnJ0c8LwDe5rdVq1bo2bMndu/ejczMTLi7u6Nz587UVjISxtPTEwzDwNfXl3X9+fPnsLW1hbW1Nby9veHo6IjOnTsTWaZxvID62yWsGx0dHeHg4IANGzZ891mauH79OoyMjBAVFYWxY8eCYRji1ZqTkwMTExM4OzsTT7uioiJ4e3vD3t6e2vESZPv27WjRogVatGjBqkB4/fp19OzZE6qqqsjNzSXGqNGjR5NnaNP5P+LSpUtwc3ODh4cH1q1bx7onOFa0bvT5HD16FJqamiKh/fx2nz9/Hvb29rC0tISzszPVxT7EvSP80EBB3r59i2PHjqFLly7o1KkTGIahvnqusBwJh0gCvATw+vr6cHd3R1xc3Hc/QxNPnjwBwzCIiIhASEgI5OTkiF68cuUKWrdujS5duuDu3bsAeB5ePj4+sLW1pVov8n/vu3fvQkpKCnJyciyP/uvXr2PQoEGwsbHBwoULcefOHfj4+LA8kmnunzD8/l66dAmamppwdXXFkydPRHS7uMITNLJz505oamqKjcIoLy/H3r17oa2tjbZt28La2ppq3fgjampqUFlZidDQUAQEBEBeXh4Mw7CS3Tfwv02D4UnCEVwAPHv2rN57hw8fxvjx4yEjI4OZM2ciMzPzl7Xx/4I7d+6gWbNmIvlmALCMF4KGKFo3IFVVVRgxYgQKCgpYi4HMzExW+AF/0ikrK8PFixfJs7Qu+n5mkqytrcX9+/fJBmTChAm4cOECtd5pISEhxJMEAJydncEwDIYNG0au8fNuXbx4Eebm5mjXrh2sra3Rv39/qpNCCvLp0yf4+fkhJiYGRkZG+OOPP1j33759i6ioKAQFBWHMmDHk3aJVFgXzDAhWjeEj2O6LFy9i4cKFUFRURO/evREeHi42gS4N8BPYAzwvJ3V1dTRr1oyVIBfgVTGytraGtrY2edcsLS2pl0e+DklNTQXDMJCVlUVcXByrIt+dO3cwbNgwMAyDdu3awczMjOqF+s+8I4WFhQgJCYGBgQGCgoLw4sULlJWV/YLW/d+RmpqKrl27suZd4U3v27dvJSZvSXl5OY4cOULyGfH7IjgfCJKZmYmoqCiq+8TPZQTwwnnEwR+b9+/fY/bs2XB0dCQeiHfu3PkVzfzbXLp0ieiA3NxcSEtLo1mzZiQMkt+nvLw8qKurw8LCAu3atYOdnR2srKyo14t8tmzZAikpKTRv3hzBwcEsWbt58yamTZsGBQUF6OnpSYQB42d+75s3b6Jz584wNzfH6tWriZcvH1rXIILExMTAw8MDVVVV9XpSf/36leVFTrMe+R6C/Xry5Ak2btwIPz8/ie1PA//3NBie/iXMmDEDgYGB+PjxI+u6oBKoqanBsWPHMHjwYNjZ2WHOnDkiZexpQNwk+erVK5iYmGDVqlVkMuUr6MzMTMTHx//SNv6nuLq6wsnJiZyA7Nu3D40aNcKaNWtYzwlPqrQujC5cuED+vXDhQlbIWX2sX78eEyZMgJaWFtauXcvaXNJAZWUljIyMoKenR9yEFy9ejOjoaMjIyCAsLIw8y59Uq6ur8eHDB3z48EGiEuYCPNnicrnYsGEDOnbsKGJ8En4vae3XkSNHMG7cOJSWlmL8+PFo27Yta8PFR7g/r169Qnp6OubPny9SypkG4uPjYWRkhKysLADA3r170apVK3To0AFRUVF48+YN6/mLFy8iJSUFUVFRSE9PlxjvVoB3iPL161esW7cOcnJyYvt3+fJllvGe9n7Fx8eTsB9xFBUV4cyZM7CysoKbmxu6deuG27dvU6vzhUlOToauri4rnx2Xy0VNTQ22bt0qEYUjBElPT4ecnBx27txJDNHZ2dlgGIalH8SND42ymJWVhQEDBuDbt28IDQ2FioqK2OTMAFiHXFwuF+vWrUNaWlq9xqrfyZw5c6Cjo4Ps7GxUVlYiPz8fTZs2JZ5P7969A/CXvr979y527dqFhQsXYu/evRKjPwDg2rVrePXqFc6dOwc5OTmRKnVlZWV49uwZLly4IFEGjOTkZDJO9REWFgZ/f39oaWlh6dKluH79+i9q3T+HL1tBQUFwcnISuV5bW4sTJ06IOA1Iis6vj/oMnZIgiw3892kwPEkogi92Xl4eLCwsRPKU1PeZ6upqVFVViZQ4pgHBSbS8vJx1ujF48GDo6emxEh1XVVWhR48eGDBgALWnOoII9i8wMBBubm5YunQpZGVlxYb6SAKvXr2CjIwMgoKCMHXqVMjKyn73ZFR4Ur137x51uatKSkoA8E6InZ2d0bZtW1ZoXXp6OqSlpTF16lTW54QX5pIgk8KUlZUhLS0NHTt2xODBg8l1cZ4MNJKQkABjY2NYWlpCWVlZrMeTMJKw0Dt+/DgCAwNJtZ+qqip8/PgR0dHRMDc3R2Rk5A/fI0nopzArV64kxqf6+kdjvwR1fVpaGjQ0NHD58uWf+uzt27exbds2VuU0WqjPYHT69GmoqqpixYoVrAOtyspKdO/eHcuWLftVTfw/IyEhAe3atcOJEyewc+dOyMvLIzU19Xc36x9x/vx5MAwDY2NjKCgokPmMZl3+MxQXF8PFxQU2NjasVBIHDhwAwzCYMmUK3r9//93voFF//Ghcjhw5gpYtW7KMT8KfodW4K9iu1atXg2GYeg1JgmNTVlaGrVu3Ijk5GRcvXvyvt/PvUt/vvWfPHkhLS4tUH3z37h0CAwPF5vf7NyHpOqaB/1saDE8STlpaGsaOHYvg4GAA9E40P4Ng22NjY+Hm5oZWrVph+PDhyMvLA8ALdeJviCMiImBvby9ReXQAdjignZ0dmjRpIpGl2wXJz88nuQf4+RNoXMz9DL169cL48eOJ92BpaSkcHR1Zxqfa2lps2bIFTZs2xYQJE/DkyRP4+PggICBAImTwR5SVlWHjxo3o1KkTfHx8fndzfgpB/REQEACGYTBo0KB6T/XFQePYrVy5kpUEvnfv3ujWrRuys7PJM/wS03PmzCEnx8OGDaM6oafgZkmwzLe4OWzlypWQl5dHTEwMy6NGErhw4QJCQ0NJ/qbvyRjtOlNwbDZv3owFCxZgzJgxZNMYHR0NeXl5zJ07F8eOHcP58+fh4eEBCwsLiTrtFuzn+vXr0apVKzRt2lTEI1kSEMxN1b9/fzAMAz8/P3z9+vU3t+w/Y+3atUTuSkpK4OTkBAsLC+zZs4eER2ZmZoJhGISHhxOjdb9+/ZCTk/O7mv1DBHUhAFJpT5zeOHLkCOTl5TFixAgq564fcfr0aSQmJv5wPMRVKaQNQZ2xf/9+rFmzBqmpqeTga/To0Wjbti2Sk5Px8eNH3Lp1C76+vrC0tKRe7zfQwP8lDYYnCWfAgAFgGAaWlpZkIUGjUv47zJkzB+rq6ti0aRMKCgrQpk0bdO3alfQvJiYGffr0gZeXFyZNmkQWtJKivPnjc/jwYcjJycHS0hIODg64evWqRI2d4ER76dIlSElJoUWLFqz8R8KbSEnoX3JyMhiGwcyZM1nGJycnJxHj065du9C8eXN07NgR5ubm1OdU+DuUlZVhzZo1GDhwoEQZtCsrKxEbG4vIyEhYWVlhwoQJePz4MQDJM8zn5uZCQ0MDQ4YMIdf4xidHR0cSdgfwSkxbWlrC09MTjo6OUFVVpX6zX1VVhaFDhyI/P5+lv3fu3ClSHpx/Mi5YqY9muFwuCgsLISMjA2lpaYn0+KmPadOmoVWrVhgzZgzc3NygqamJhIQEALxDIxsbGzRp0gTm5uZwcXGRmBw6gvDfnVOnTkFGRgZqamrYvXs3MWpIGlVVVdiyZQs2bdoEGRkZDB48GC9fvhT7LO168vDhw9DU1MT48eNx+/ZtAH8Zn6ytrZGdnU3K0WdmZkJKSgo+Pj6wtLRE+/btqc0pyefbt2+wtLQknjD89h44cIBVqh7gJfVnGAaxsbG/vJ3/CQUFBWjUqBFkZGSI4Yl2ufsZpk2bBl1dXTg4OMDf3x9SUlIoLCzEkydPMHfuXDRr1gytWrWCgYEB7O3tJVI3NtDAf0KD4UmCqG8zy4/XX7ZsmUSfYnG5XDx69AimpqakdDs/Xl9cGBrticTFJRHk/1vY9bZfv35wdHRk5UqSFHJycvD27Vu8e/cOp0+fhoKCgkh+IEmBPz7p6elgGAaRkZHfNT4BvFDDU6dOSVROhZ+lsrJS5ASWZuLi4jBjxgzy94oVK2Bubk680vjUlyCYNkpLS5GUlAQLCwsEBQWR62fPnkWfPn1EjE9JSUmYNGkSRowYITEGeS8vL3Tv3p0kTt+3bx8aN26M1atXA2DLXVZWlsS9X1u2bIGSkhL8/PyIN6gkk5OTgzZt2hBvk5MnT4JhGFZhjM+fP+PmzZt4+PChROvFzMxMyMnJYfv27Vi+fDnatWuHzMxMVFZW/u6m/S1WrVqFESNGkL/Pnj0LaWlpDB48mOVBSLMnkDDJycmwtLTE2LFjf2h8ys3NxaRJkzB16lRqKx4LM3v2bMjIyJC1cFZWFlq0aIFNmzaJPHvp0iXq+yPM27dvkZCQAEVFRUyaNIlcl4R1Rn1s2bIFrVq1ImlPNm3aBIZhkJGRQZ55+PAhDh06hPPnz0u0bmyggX9Kg+FJQhBUxk+fPsWLFy9YyVZHjBiBdu3aISUlhVXRiXaEJ5nHjx/D1NQUAC+Rp6ysLJKTkwHwPDCysrJEqlrQ6F3CX/AAEEls/OHDB/Tt2xfr169nXXd1dcXYsWN/Sfv+L+ByuSgoKICMjAxZvNbV1eHQoUNQUFDA0KFDybPjxo3D1q1bf1NLfw5hWUxLS6vX+KSrqys2jIn2Tf4/hcZ3TJi6ujoEBwdjzJgxrOsrVqyApaUlgoODkZeXBw8PD1haWv6mVv48fHksLy9HYmIizMzM6jU+7dq1S+x30LygFXzfBg4cCCcnJ8THx4vNdyf8btLYL8E2CuuB9evXo3Xr1ggLCyPed5KC8Lu/du1aBAQEAAC2bduGli1bIikpCQAv3879+/dFxovGzSS/Gml9XL9+HTo6OqzwuoSEBMjKyoqtrkszI0eOhIeHB4C/xuLcuXNo2rQpBg4ciEOHDqFHjx4wNDSkXtcLvvtr1qyBubn5TxmfBNdkNOoPccTFxaFx48aYN28e5OXlyXtWH7T2q7737NOnT4iPj4e0tDSioqJ++Dyt8N+ZefPmITQ0FACwe/duyMrKkkI7JSUlYgvo/FvXjA00UB8NhicJQHAhMHv2bJibm0NRURH29vYsZT18+HC0b98ea9euxZcvX35DS/85/DjoZ8+eQUNDA+Hh4VBQUGBNtFevXoW7uzvy8/N/VzN/yN69e1l/L168GE5OTujbty82btxIrgueMgpOPLRPuMJeXKWlpdDT08O5c+dYz/CNT1ZWVrCzs0O7du2oXRQJc+PGDeJNt3HjRrHGJxcXFzRr1kziNpH/JsS9K8uXL4exsTHKyspYG42kpCTY2dlBR0cH9vb2rHs0Iq7U8po1a8Qan/gJx7dt2/arm/kfI+i12r17dzRu3BiRkZG/sUX/DEFZTEpKwpAhQxAUFISFCxeS68nJydDQ0EBYWBjL+07SiIqKQkBAAC5evAg5OTkkJiaSe2lpaYiMjBRbRZImysrKWH9nZWVh+f9j78zjas6/P35uO9qkGpUoZckSLSplSZZKFMJEylJShiypLDOWBhFlIkuW1qFshaFsYyvJlqwhTIgGKUt73fv6/dHvfr73VmYffa75PB+PeYze9/25j/O+n8/nvM/7vM/7nA0bkJaWxlTfe/HiBTOvid7fpKQkVi8Wm9KLe/bsQd++fVFZWQk+n8/MxVlZWdDT04OJiQn69u3L+qPiTcm1cePGJp1PgwYNQt++fbFnzx5W36+GCHPeCe+jh4cHpKSkGIeGJI0FaJwXbtmyZfDx8cGVK1dQXl6O6upqhIWFQUVFBStWrGD6svUZFNKUfIGBgZg1axZSU1PFNs0FAgFiY2OxdOlSpkImB8d/Fc7xJEGsXLkSampqOHLkCJKTk7FixQq0bNkSc+bMYfpMnz4dSkpKOHToUPMJ+ic5ffo0eDwe43xasWIFWrRoIRa5UFVVhREjRmD48OGsdc5ER0ejY8eOTC6PLVu2oHXr1li+fDlsbW1haWmJgIAApv+nHE5sHZ8oogsLAwMDbNy4sVGfe/fuwdvbG8HBwRJz7Gfv3r0wMjJCXFwcI3NTzqcPHz5g1qxZrB/Pf4HU1FRkZWXhzZs32LhxI6ysrJp0cubn5+PGjRsSFd4eGhqK48ePA/i08ykzMxODBg3CN99801xi/iGaioIRGu/p6elQUlKChYUFbGxscPXqVdYvPJoiODgY6urqmDNnDkaOHIlOnTrB0tKS+Tw6Ohrt27eHt7e3RCVJX7lyJYKDgwHUv0daWlrg8XiIj49n+lRWVsLJyQk+Pj6svncLFy7E+PHjmc25+fPnQ1NTE4aGhujSpQvc3d2Z8uai42io69mu++Pi4nDmzBncvn0bycnJ0NTUbHKj5MWLF8jLy5Movbhz504sW7aM+ftTzqcePXrA29u7maT8YzRl7wmfrZSUFCgpKWHMmDGQlpZmKjqz/dlrioCAAKirq2PkyJHo3bs3vvrqKyxbtgyvX79GRUUF1q9fjzZt2mDBggXNLeqfIi4uDj/88AMAMNWAFRUVmaPiQP3c7ejoKJGbKhwc/zSc40lC+PDhA4YNGya2u1heXo6EhAQoKysz4ZwAsGbNGomamIqLi2FnZ4fQ0FAAwJ07dzB16lSoqKhgwYIFWLBgAQYPHozu3bszO3JsdM4UFBRg5syZsLKyQmhoKIKCgpCWlgagfuJZvnw5zMzMxCZWSbpPQsLDw9G1a1d4eHhg9uzZcHJyQnBwMH755ZffvE4SDNq3b98yOWcSEhIaOZ+WLFnSqDSzJN7DL4Xbt29DTU0NhoaGUFdXh4WFBXg8HqZOnYo9e/YgKysLBQUFKC8vF7tOEu7Zx48fMXbsWPB4PJw9exaAuPNJNOH4zZs3WakTm2L58uVMPiegPkpUTk6OcWJMnDgR/fv3x8WLF5tLxL9ETk4OOnTowBzDEggEuHjxIoyMjGBra8v0i4yMlLjql5GRkTAyMkJeXh5qa2sRGRkJPT09zJs3DwUFBTh37hwcHR1hbGzM6gqzAoEA3333HaytreHr64vs7Gw4Ozvj+vXrqKqqwo4dO2BrawtnZ2c8e/YMADttjd/j2rVr6N27N9q3b4+WLVvCxsaGqWa3bds2pKSkoKSkBE+fPhW7ThLG+v79e3h7e6Nnz55Yt24d0y50Ps2cOZNxPpWXl0uErgeAsLAwJCUlMX8fOHAASkpK2LZtG4D66Hl5eXkcPXq0uUT8yxw/fhza2tq4ceMG0/b999+jZ8+eCAsLAwC8evUKy5cvx7Bhw1ipO5qisrISjo6OGDlyJNM2btw4KCsrY9++fXj8+DHu3r0LBwcHmJmZSYQNzMHxb8M5niSE0tJS6Ojo4LvvvhNr//jxI8aNGwdfX1+J2JH7lGEzd+5cGBsbM38/fPgQmzZtgpmZGVxdXREQEMDqpJDCcRUWFsLX1xc2NjbQ19cXS2JcUlKCFStWwNzcHIGBgc0l6t8mNjYWW7duxcyZMzFkyBC0a9cOPB4PxsbG6NevH8aNG4dFixYxyWfZSHFx8SeNm9LSUjg5OcHa2lrM+SRMFCk0BDk+P03pjw8fPuDDhw/4+eefceTIEUhJSaFdu3awsLBAq1at0Lp1a/j6+jaDtH8Oob4WfS4LCwvh5eUFGRkZxqHx7t07bN68GWZmZhgxYoTYd7Bx4Sg6nh9//BEqKio4f/48gPp37euvv26U787BwaFRri62IfytheNLS0uDmpqaWO7F2tpapKeno2vXrkySYNFr2Hi/muL69eswNjZmimE8f/4cUVFR0NXVhZqaGnr16gUnJydWV2gS/c3XrVuHgQMHwsXFBaNHjxY7epuQkMB8JnQ+sX0h/KnqsW/evMGjR49w6NAhaGpqws7ODkZGRtDU1ISGhgZcXV2bQ9y/zS+//IL58+fDxMQEa9euZdo3bdoEc3NzTJw4UWwjjI3Po+g9i4mJgba2Nq5evYq6ujrU1dXB1dW1UU6nb7/9Fv379wfA7mey4e+dnJyMzp07o6ioSOyzRYsW4auvvmKKIr1//77JojxsRChfbm4uFBUVxY66Dx8+HD169ICsrCysrKwwYMAAVutGDo7PCed4YiG3b99mjNf58+czlc5mzZqFESNGMLs5Qvz8/ODk5PTZ5fw7PHv2TKwscVlZGXR1dbFkyRKxfg3L3rJRaTc0+p4/f46ZM2dCSUmpUWhtSUkJvv/+e+jq6oqF4rKV30qYK/zs+++/R/v27ZGVlYWQkBBMmDAB48aNY+W9AoCePXuK3ZfExEQmMk1ISUkJhg8fDmNjYyQlJTHOp2PHjrHS8flfQPRZvH79OvOfKBUVFRgyZAhTYevBgwe4fv06q+/ZggUL8PDhQ+bv169fA/ifYfvixQtMnToVsrKyOHPmDIB6A33t2rWYMmWKxDgvTp48iTlz5ojlugMgVixCUvLdCY/cAsCpU6cA1Ee86uvrix0/A+qrN2loaDSqRsXGhZWoTA3zoM2bNw/t2rVDSUkJ07eiogJXr17F06dPJeKollBGPp+PNWvWwMjICHp6eo2q1CUmJsLOzg42NjaNIlzZhuh7cvnyZfz88884d+6cWJ+amhr06dMHmzZtgkAgwPv373Hx4kXWztEAsGTJErEImYbFPAoKCjB37lyYmJiIRT6FhoZKlF68dOkS5s6dix07dgDA775HbNQbn+Ly5cuoq6vD7t27oaGhwehNYZ6jd+/eoXXr1jhy5IjYdWwcY1MyCQQCVFZWwsvLC9OmTRMr7HT79m2kpaXh1q1bEqEbOTg+F5zjiUUIBALk5eWhTZs2WL16NXx9fcHj8XDz5k0A9WWmjYyMMHfuXKbt/fv3GDRoEGbPnt2cov8pYmNjoa+vDw8PDzx48IAxfr7//ns4ODjg119/ZZIrst14EJUvMTGRiUooKirCzJkzYW5ujvDwcLFriouLERMTw2qjDxAf2+bNm+Hn5wdnZ2dER0eLLRazsrJgYGDQ6DhTw+9gAytWrICxsTEjV01NDTp37owBAwY0qlRUUVEBPT099O3bF1u3bhW7X5wB8XkRNfqWLFmCLl26oFu3blBVVUVAQIBYtRhXV1fmGNpv5WhhA0OHDoWNjQ3zPKWmpkJOTo7R70L5CwsLMW7cOMjLyzPFFcrKyiQmciYzMxPGxsZQU1NDcnIygE+/Q2zPd3f06FG4urril19+wZw5c8Dj8fDq1SuUlJTA2dkZTk5OYrqktLQUpqamjDNUEoiIiMDixYvFjjsWFhbC0tKScV403BQC2Hm/gKbl4vP5iIiIQKdOnTBt2jQxZyIAbNu2Dd988w1rxwSI67eFCxeie/fu0NfXh4WFBQYNGiQm+7x58zBt2rRG38FGvWhvb4/u3bsz4zt06BC6devGRNwJefLkCSZNmoQOHTqIpaGQBL0oEAiQk5MDeXl5yMnJMblBgd+Xm42OGaB+jSKMops7dy4GDBiA8vJy1NbWomfPnhg4cKBY//z8fHTq1EmijlVv3LgRmzdvFnMyJSYmQklJqdFGmChsfhY5OD4nnOOJhWzatAmqqqpQUFBgdlOFJCQkoFevXujevTsGDBiAPn36oEePHqyvRiJKdXU1NmzYgFGjRkFRURH+/v44e/Ysnj17BkVFRYky0IUEBgZCS0sLkZGRjAH7/Plz+Pn5wdLSspHzSQgbjb6GBAUFQUNDA6Ghofjmm2/QuXNnjBs3jtkRz8vLg4KCgpjxIKzMwjbmz58PU1NTAPXJLvfs2YPCwkL06dMHgwcPZpJ3CnFxcYGGhgZmz57NyvH81wgLC4O6ujrzrAUHB4PH4+H69evMuxQcHIxBgwY1p5h/iAcPHqBbt25MFFNWVhZ+/vlnjBw5Eu3bt8etW7cA/M9gPXjwIHg8Hng8Hq5cucJ8jyQ8l7W1tQgNDYWuri6GDBnCJHaWRGM8IyMD2tra6NatG9TU1HDnzh3ms7t378LCwgK2trYICAhAUlIS7OzsYGxsLBG6XkhwcDDs7e2hoqKCoKAgJoLGz88PdnZ2zSzdn6NhRNDNmzeZY+ACgQDr16+HlZUVfHx8mGiu3/oONhIREYE2bdogOzsbfD4fq1atAo/HY3QLAKxfvx6dO3dm/XOYn58PU1NTRsdfunQJOTk5GD9+PAYOHIjExESx/ufOnYOysjI0NTXFog0lQS8C9U4LNTU1jBgxAnl5ec0tzl+mtrYWe/bsgaamJoyNjaGiosIUDAKACxcuwMDAAObm5khPT8exY8fg5OSEPn36sP6ZFFJeXo65c+dCXl4eI0aMwLfffst8NnnyZDg6Oja5AcvBwfE/OMcTS2hY4UdNTQ2amppYvXo1k2dAyKVLlxAXF4eZM2di/fr1rM591JCGMsbExDDJ+IROgW7duqGoqKiZJPzzbNu2DZqamsjJyWGcMcJ7KTx2Z21tLVYqVlK4cOECOnXqxCQDPnr0KBQUFBgDTzjODh06ICUlpdnk/D2EcmZkZMDIyAjGxsZQVlbG/fv3AQBPnz6FqakpBg8ezORiEQgE8Pb2xvnz5xvlc+H4/AgEAnz99ddMieL9+/ejdevWTB4M4dHd7du3MwlK2Xy/Hj58iE6dOmHVqlXw9PRE7969UVpailu3bmHUqFHQ1tZmIp+AeseUj48PNm7cyGpd31T1OqDeyb5+/Xqm+pQwrwfbF/VCRJ8nb29vSEtLw8HBgdEhQu7fv4/58+ejW7dusLS0xKhRoyQyv8fbt2+xf/9+mJmZoVevXpgyZQpOnjwJGRmZRjm5JIGAgABoampCS0sLampqCAgIQGVlJQQCAcLCwmBtbQ0/P79GkU9s1iFAfdTu5MmTmQIzhw4dEis4I6xAu2fPHowcOZL14yktLYW2tjamTJmCWbNmQU5ODnV1dbh58yYmTJgAGxsbMedTdnY2xo8fj+joaFa/X7+VtmDnzp3Q0tJCQEBAk5UHJQlnZ2fweDw4OjqKtdfW1uLmzZuws7ODrq4ujIyMMGzYMInUjfn5+Vi0aBG6du0KAwMDREREYMmSJXB2dm50JJSDg0MczvHEAkQnJNFd7sjISOjo6GDZsmV4/vx5o+vYfIykqYW6qHNNlHfv3iEzMxODBw9GmzZt0K9fP1YbRw1l8/b2hp+fH4D/3QfRe/ry5UtMmDAB06dPZ/W4gMaLwJSUFPTu3RtA/UJfSUmJWfiXlZUhPT0d1dXVWLZsGasXw6LY29uDx+M1yov29OlT9O3bFxYWFnB0dMTAgQPRo0cPsYUzR/Px4cMH6OnpIS0tDZmZmVBUVGSexerqaixYsADXrl1DcXGxxDgKk5KS0KpVK7Rq1QrHjx9n2nNzczFq1ChoaGggPT2dcUb5+Pgwfdj4vonqjx07dsDX1xfe3t6Mo5rP52Pt2rWwsrLCzJkzGecT2++T6LgEAgEOHDiA+Ph4GBgYwM3NjTliIZoYt66uDm/evGHa2Ha/mtJnQrlFKSoqwqlTp9CnTx90794dPB5PIo72iz5TmZmZ6NChAy5cuIBLly5hz549aNGiBdzd3QHU39+wsDAYGhoyVbbYSsN3RSAQoG/fvtixYweOHz8ORUVFxhkvdPampqairq5OLMcVGxHKlZeXB1lZWSgpKeHatWvM57m5uZg4cSKsrKywevVq3Lt3D8OHDxeLSGbjPC36e2/ZsgWenp7w8PDA6tWrmfatW7dCW1sbAQEBePLkSXOI+ZcQHdv79++xc+dOhIWFoUOHDvj666+Zz0Tvy/Pnz/Hs2TOJzn1UW1uLyspKzJ07Fy4uLlBRUQGPxxNLds/BwdEYzvHUzIgaEd9++y0MDAzEwoXXrVsHHR0dhISEMJFPzs7OYpMxW6mqqsK0adOYBINC9u3bJ3acTvgblJWVITs7u0nnDVsQvV/CpO99+vTB1KlTG/Wprq5mIhZev34tMYthAMxRnmPHjsHe3h4pKSlQUlISq7KSlpYGX19fvHjxgmljo9Enytu3bzFixAiEhISgW7duzMJDSFFREZYvXw4PDw/MmDGDMYjY+Cx+ydy8eZPJI7ZixQqmOuSiRYvQt29fKCgoICYmhun/5s0bDBo0CBs3bmTa2PyeCWWLjo4Gj8eDoqIiQkNDxXJV3bt3D1OmTAGPx4OhoSF69+4tMUeqAwMDoampCTc3N7i4uIDH48HLywsVFRWoq6tDaGgobGxsMHHiRJSVlTW3uL+J6Lu/du1a+Pr6Mvk9zp8/D319fbi5uYklQm54XJyt96u8vBwnTpxgogWFcopWYxVl3759WL58uUQtFGNiYuDl5YWAgACx9osXL0JaWppxNPH5fOzevZvVc1hOTg7evn0LoP44ZFJSEvNvOzs7KCsrM854oH4+Gz58OCIjI5k2tj6LoiQmJkJWVhYtW7bE9OnTxZ6327dvIzAwEKqqqujYsSMsLCwkRi8GBwdDXV0dc+bMwciRI9GpUydYWloyn0dHR6N9+/bw9vYWs6vYiqhu3LZtG7Zt24Znz55BIBBgz5490NXVhZubm9g1Z8+eFStcIKm2leiz9uTJE8TGxmLEiBESpRs5OJoDzvHEEpYtWwZ1dXUm15Eo69evR4cOHeDs7Axra2toaWk1mdiTjQwePBi2traMo0xY7jwqKkqsX8PJh43GX8MEx0ZGRnjz5g1WrVqF7t27IzMzU6z//fv34ebmxkSxAeydZPfv34+5c+cC+F9SyIqKCnz48AE6Ojrg8XhM6D4AVFZWwtHRERMmTGC9sdeQuro6CAQC7Nq1C127dm3kfGo4Hs6Q+Lzk5uaiW7duWL58Ofz8/MDj8Zg8OqmpqTA2NsagQYMYw/zNmzdwdHSEjY0NK/XGb1FQUIB3795hx44dUFJSwvLly5mKpkKuXr0q5rxn+/OYmZkJLS0tsZxvp0+fRsuWLeHv7w+gfgyLFy+Gj48Pa3ViQwIDA6GtrY0NGzaIVSEU5i4ZO3YsEhISMGLECKirq38ywpdNJCQkQElJCXv37mUqTaWkpIDH4+HChQtMv6beK7Y/h0B9ZIWzszOUlJQwZcoUAPX6XbjwXbx4MaysrBrldmKjHnny5Al4PB6Cg4Ph6+sLJSUlRi9eu3YNWlpa6NOnD5Mn6MWLFxg+fDj69u3LyvH8Fjdu3EBhYSEyMzOZeyeqJ8rKylBQUIBLly5JTNRMTk4OOnTowBQeEAgEuHjxIoyMjGBra8v0i4yMhIuLC+t1hygLFiyAuro6YmNjmc2TiooKJCUloX379hg9ejSeP3+OYcOGYdSoURI1tt/iU+Ng+7PIwdGccI4nFvDy5UtYWloy1X6EiDqXYmJiMHfuXPj5+UlETidRI2Hs2LEYMmQI1q9fD0VFRezatasZJfv7XL16FSNGjGAWVhcuXIC1tTXc3Nxw9uxZAP8zePv168d6o08gECA+Ph48Hg99+/aFkpKSmLMsKysLbdu2xahRo3Dw4EHs27cPQ4cORY8ePZhnUBINibKyMsTExKBr166YNGkS0y76XkniuCQVYR4xoD7K6auvvkKLFi3EEuQC9cUXLCws0L59e9jY2MDMzAxmZmYSmStClMjISMb59Kkcd2wcW0OZ0tPTYWBggJKSErGjW6mpqZCXl2ccGqKOGbY7n06ePAkdHR1kZGSItQvlvnjxIvMsDho0SGIiMAAgPDwchoaG+Pnnn7F3716oqKggOjq6ucX6x8jIyMDYsWPRokULseOsALBmzRpYWlqyeiPvypUrjHzp6emQk5NDixYtmITvwmfw/Pnz+Oqrr2BqagpDQ0NYW1vD3Nyc9Xrx996REydOQFlZWcz51PAaNuqPhrKmpaVBTU1NbGOhtrYW6enp6Nq1K5NbUvQaNo6rIXv37oWOjk6TpzDKy8tx+PBhtG/fHh06dJCo6LS/wpc4Jg6OfxrO8cQC7t27hxYtWjQq5w5ArEKCqHHEZqeTEFF5ra2tISMjg8WLFzejRH+f+Ph4DB8+HHZ2dkzSTqA+oefw4cOhrq4OAwMDdOvWDaampsxvwEYDwtfXV+xIxaBBg8Dj8ZidYaB+IuXz+cjOzoaJiQkMDQ1hYWGBr7/+mvUG7R+hrKwMsbGx6N69O4YPH97c4vxnCQsLQ7du3bB//34AwOHDh9G2bVt06dKlySig7OxsbNu2DcuXL0dCQgKro4FEFyCiC4qmdEJkZCRUVFQQEhIiEUcthDmaAOD69euMrpCSkhJzMAHAs2fP0KFDBxw+fFjsOyTBWI+OjoalpWWTTmnhs1dUVCRReUtEn7+dO3eibdu2UFBQaBSNLCmIjqfhu5WVlYWxY8fC0NAQaWlpqKmpQWlpKezs7FgdXfLdd99BT08PKSkpqKysRFZWFhQUFJjIp19//RXA/57FvLw8HDhwAKtXr8bhw4dZrRcbOleEOaiauhcnTpyAiooKpk2bxtp7JYpognphZeqCggLo6+uLpdIA6vWGhoYG4uLixNolYZwAEBISgmHDhqGqqkosx50o7969EyvSwsbnkYOD4/PAOZ4+M01NJoWFhTA2NsbGjRsbOSr27dvH+mSXn0I41uPHj0NJSQlmZmYYMGAArl+/LjGTakOioqKgp6cHNTU1JqGskMePH+Ps2bOIiIjAgQMHWG30VVZWolu3bujYsSNThWPt2rVYsWIF5OXlxfJhCOWvrq7G69ev8fr1a9YmzP0rlJWVISoqChMmTGClg/C/wOnTpzF27FgMGjQIx44dQ1VVFYqLi7FixQqYmJhg0aJFv1vpks0O0KqqKkyePBlZWVlicu7du7dRefBNmzaBx+OJ5bBiI2fOnIGLiwvevn0Lf39/dOzYEcXFxSgrK8P48eNha2srFsX29u1bdO3aFYcOHWpGqf8aW7duhb6+vpgzUCAQoLa2Fj/++COTd0eIpOgRof4+e/Ys5OXloampiYMHDzI5nyQF0d97+/bt8PT0hLe3NzZv3sy0Z2RkYNSoUeDxeOjcuTOmTJkCS0vLRvmt2MT79+9hZ2cHKysrHD16lGk/evQoeDwe5s2bh1evXv3md7BZL9bU1MDMzAzHjh1j/gbqxydaqh6ojzrk8XhYtWrVZ5fzz3D06FG4urril19+wZw5c8Dj8fDq1SuUlJTA2dkZTk5OYpvMpaWlMDU1bZQXju0InysPDw+xo4LC9rq6Ovz8888oKCho8joODo7/Jpzj6TMiahyVl5czyXMBYNKkSejYsSNOnz7NtFVVVWHkyJFwc3NjpVEkpKldDuG/Dx06BDk5OSQkJAAAxo8fj4EDBzKJudnMp37zPXv2oEuXLnB3d2dyLHyqPxsn2Q8fPgCoL7M8aNAgdOjQQexoXUJCAuTk5DB//nyx64THCIWw+Zn8swjLagOSs2j8EoiMjGR+94yMDIwZMwb9+vVDSkoK02fJkiUwMTHBd999x+zwT5kyReLKFjs4OKB///6MM+bIkSOQlpbGpk2bAIg/d/v372e9Uzc2NhYDBgyAkZER1NTUxMqAHz9+HCNHjkTPnj2xfft27N27F/b29jAxMWGlThTyqXf/3Llz0NDQwA8//CCWD6iyshL9+/dHRETE5xLxH2ffvn1QUlJCUlISNmzYAENDQ+zbtw+VlZXNLdqfJigoCFpaWpg9ezZmzpyJ9u3bIzAwkPn80qVLcHNzQ8eOHcVyFoomO2YD27dvR25uLoD6+drW1hampqY4dOgQ4yjbt28feDweFixYwDjlx48fj9TU1OYS+y/x7bffQl5enjlqtn//frRq1apRBBBQf+yQ7XoxIyMD2tra6NatG9TU1MRsxLt378LCwgK2trYICAhAUlIS7OzsYGxszGq9CHxaNza08YX8+uuvGDt2LONU5ODg4AA4x9NnQ1Rpr1q1CkOGDEHbtm0xdepUnD9/HkD9USdhvpng4GDY2NiwPo+OqMEmevQMqK/kNm7cOOzcuVOsffDgwfDz8/ss8v1VRO/Xixcv8OTJE7Fd4B07dsDU1BTTp0/H3bt3m0PEv8To0aPxzTffMKHgHz9+xMCBA8WcT3V1dUhMTISCggJmzZqFJ0+eYPjw4aw+kvBP8aWPj02kp6dDW1sbnp6eTJvQ+TRw4EDm2B1QvzgxMzODvb09Bg4cCA0NDdYvQISI6pIJEybA1tYWYWFhTea7a2jcs3GMou+Ih4cHeDwehg4dKlaRD6jPfTdnzhwoKyujT58+cHJyYvXxXNHfPj4+HitXrsSMGTMYB8CKFSugoqKCpUuX4tSpU7h48SKGDRsGU1NTVt4n4H9HpT9Fbm4u9PT0xI7XhYeHQ1FRscmj/2wmLi4OhoaGyM7OBgAkJydDQUEBLVq0gI+PD9Pv3LlzcHd3R8+ePZk8SWzi+PHj0NHRwTfffMPYFkLnk4WFBVJSUhi7a9++fZCVlcXw4cNhZmaGTp06sTpf1acIDQ2FtLQ0li1bBhUVFbHquU3BxvdN9Ci1t7c3pKWl4eDggPv374v1u3//PubPn49u3brB0tISo0aNYrVeBMR1408//YSoqChER0fjwYMHAAAfHx906NABW7duRXFxMe7cuQMnJyeYmZmxdkwcHBzNA+d4+sx89913+OqrrxAXF4fLly9DV1cXlpaWTK6MkJAQuLq6wsHBAf7+/swEyzbl3TBPx9q1a2Fra4tx48YhNjaWaRc9miA6BjZHlYjKtnTpUlhaWqJFixbw8PAQO58fHR0NMzMzscUJ29m6dSt4PB4WL14s5nyytbVt5Hw6cOAAWrZsia5du8LExOSLTgrJ8fn5+PEjtmzZAlNTU3h4eDDtGRkZcHV1beR82rJlC/z9/TFt2jTW6sVPIboY7N+/P6SlpbFo0aJmlOiv0bCy1NatWxEeHo7BgwfD1dW10SILqM938uHDB4k5nhsYGIi2bdtixowZGDJkCHR0dBAeHg6gftPIysoKMjIyMDExgZ2dHWsXjWVlZWJ/79+/Hxs2bEBaWhpzNPDFixdMNVbRe5uUlMS68TSkoQ2xadMmhISEAKiPJlRVVUVERAQiIiLA4/HEIp+ysrLg7u6Odu3aMRt/bGLr1q0wMzODn5/f7zqf0tPT4e/vj/nz50tE4RkhQkeN8D56eHhASkqKqa7L9udPFNFnUSAQ4MCBA4iPj4eBgQHc3NyYtAyipwPq6urw5s0bidGLQL1u1NfXx4ABA+Ds7AxZWVnk5OTgyZMnWLp0KVq0aIG2bduic+fOsLGxYa1u5ODgaD44x9NnQiAQ4NGjR+jVqxcTUixMFNlUlTc2JxKPjo5Gx44dmeMFW7ZsQevWrbF8+XLY2trC0tJSLEfQpxxObHY+AfVOJw0NDaSkpCA7Oxu2trbo2bMnczQGqI98ateuHdasWdOMkv4xhAZOQkICeDweFi1a9JvOJ6A+/9jZs2e5pJAc/yjC56m8vBybN29G7969P+l8OnDgQJPfwdZnsaFeE02Ym56eDiUlJVhYWMDGxgZXr16VGEeu6LjWr1+PDRs2MEd84uLiMHDgQLi6ujK74EB9HqiKioomv4ONpKamQldXl9lIOHPmDHg8nlj+lZKSEty+fRv5+fms1YsLFy7E+PHjUVpaCgCYP38+NDU1YWhoyBwTF+ZeEX3+Gi4QJWHBGBoayuRUfPz4MYqKimBsbMzkxrx58ybatGkDHo+HlStXMtdduHABXl5eYkdEmxvR5ygqKgomJiZ/yPkkGnnOtmdRSFPvvvD5SklJgZKSEsaMGQNpaWkm5YQkPH+i41q7di18fX3x/v17APWVBvX19eHm5oYbN24w/Rrmc5KEOSAxMRFt27bFlStXANTrfB6Phz179jB98vPzkZaWhosXL7JWN3JwcDQvnOPpX6ThRPv48WP06tULQP1Eq6ioiK1btwKo353cv3+/WN4ngJ0TUkFBAWbOnAkrKyuEhoYiKCgIaWlpAOqrVyxfvhxmZmZYsGABc40kGBCiZGRkoGfPnkxlpvPnz0NBQQH9+vWDsbExtm3bxvQVrR7DVho+izExMZ90Punr6zeZP4ftY+SQDJqqeBMVFdWk80mYcHz37t2fW8y/zfLly8WSax8+fBhycnJM1OTEiRPRv39/XLx4sblE/EsII4I2btwodrwuPj4ednZ2cHJywqlTp2Bvbw8LCwtWzmFCGsq2fft2uLi4AAB2794NZWVl5tjP+/fv8eDBgyYdi2xCIBDgu+++g7W1NXx9fZGdnQ1nZ2dcv34dVVVV2LFjB2xtbeHs7Ixnz54BYN8YfgtRWePi4qCtrc0crwPq5+pOnToxY7t79y7c3d2Rnp7eaA5jUx6rpt6TjRs3Nul8GjRoEPr27Ys9e/ZI3LwcFhaGpKQk5u8DBw5ASUmJsanWrl0LeXl5sWTqkkBgYCC0tbWxYcMGPHz4kGm/cOECDAwMMHbsWCQkJGDEiBFQV1f/ZAU/tiGUcdmyZUw02sGDB6GoqMjkSfvw4UOjo9YAZzNycHA0hnM8fQaEO8AFBQXQ1tbGggULoKqqKnaO/fr16xg6dCiysrKaS8w/hNDoKywshK+vL2xsbKCvr4+cnBymT0lJCVasWAFzc3Ox8HZJoqioCBs2bEBNTQ1OnjyJNm3aICYmBr/++isMDAzQpUuXRtVVJGGSvXXrFhNNFxsb26Tzyc7ODi1atGDVTjDHl0doaCiOHz8O4NPOp8zMTAwaNAjffPNNc4n5hxFdRPz4449QUVFhjvGUlpbi66+/bpTvzsHBATNmzPiscv4dDh06BG1tbVy7do1pE3UEJCcnw97eHrq6uhg4cKDE5ZtZvnw5XFxckJ2dDSUlJbGqaDExMVi0aFGjXIZsQrRAwrp16zBw4EC4uLhg9OjRYlExCQkJzGdCB40kLIJFycrKwty5cxEdHQ3gf8/hrVu30Lp1a3z//ff45Zdf4OjoiPHjxzPjq6urY/VYd+7ciWXLljF/f8r51KNHD3h7ezeTlH8cUf0QExMDbW1tXL16FXV1dairq4Orq2ujnE7ffvst+vfvD0AynsuTJ09CR0cHGRkZYu3CsV+8eBE2NjYwMzPDoEGDWJ+2oCm5AgMDMWvWLKSmpoptmgsEAsTGxmLp0qVi0a0cHBwcTcE5nv5lTp8+DR6PxzifVqxYgRYtWogtNqqqqjBixAgMHz6c1TuPDWV7/vw5Zs6cCSUlpUb5SkpKSvD9999DV1dX7GgaG/nUb/7x40fU1NRgzJgxWLJkCeNYGj16NHr06AF/f3/WGg5NsXfvXhgZGSEuLo4Jf27K+fThwwfMmjVLIhxpHJLJx48fMXbsWPB4PKZaoqjzSTTh+M2bN1mtFxty8uRJzJkzRyzXHQCxaFZJyXfXkKioKGbh9KmiF2/evEFeXp7EHLVYuXIlgoODAdQfFdHS0gKPxxPL51dZWQknJyf4+PiwXucLf3c+n481a9bAyMgIenp6jaJ7EhMTYWdnBxsbG7x69ao5RP1L8Pl85ObmQkFBATIyMli7di3zmUAgwIcPHxASEgJVVVXo6enBzMyM9Qt9Ie/fv4e3tzd69uyJdevWMe1C59PMmTMZ51N5eblEzdGXLl3C3LlzsWPHDgD4Xf3A9nslSnR0NCwtLcXGIuroBOo3M589eyYxehGojyj84YcfANQ7Dbt27QpFRUUxm/7du3dwdHSUyJyFHBwcnx/O8fQvU1xcDDs7O4SGhgIA7ty5g6lTp0JFRQULFizAggULMHjwYHTv3p0xjti4EBGVKTExkal4U1RUhJkzZ8Lc3JxJwCqkuLgYMTExrDaORMeVnZ2No0ePIjc3l3HC1NTUwNTUFAsXLgRQn0thwoQJSE5OFksUKQm8ffuWKemekJDQyPm0ZMmSRgsQNt87DslB+ByJviuFhYXw8vKCjIwMo0/evXuHzZs3w8zMDCNGjBD7DjbqxYZkZmbC2NgYampqSE5OBvDpBYYk5bsTsmjRIujq6jJ/C+9rXV0dzp4920h/SMK4IiMjYWRkhLy8PNTW1iIyMhJ6enqYN28eCgoKcO7cOTg6OsLY2JjVFWab+q35fD4iIiLQqVMnTJs2jZnXhGzbtg3ffPMN6+9TU793cnIyNDQ04ODg0Kiy7IcPH5Cfn4+zZ88yz6gkLPQB4JdffsH8+fNhYmIi5lTbtGkTzM3NMXHiRPzyyy9MO9vnaIFAgJycHMjLy0NOTo7JDQr8vn5g43vWFFu3boW+vr5YMR2BQIDa2lr8+OOPTDJ/IWx/34B6Z7ujoyNGjhzJtI0bNw7KysrYt28fHj9+jLt378LBwQFmZmYS835xcHA0L5zj6R/kU5PJ3LlzYWxszPz98OFDbNq0CWZmZnB1dUVAQIDEVCMJDAyElpYWIiMjGSP2+fPn8PPzg6WlZSPnkxA2GkeiRs3ChQuhr6+PHj16wMjICC4uLsjKykJ1dTUmT54MOzs7zJ07F4MHD4aJiYnYrjLbKC4u/qTBVlpaCicnJ1hbW4s5n4SJIkVzV3Fw/F0WLFgglu/i9evXAP737r148QJTp06FrKwszpw5A6B+13/t2rWYMmUKK9+v36K2thahoaHQ1dXFkCFDmOTOkjaOT8l78eJFGBgYYM2aNaiqqmLaS0pKYGdnJ5ZoVlK4fv06jI2NkZCQAKB+PouKioKuri7U1NTQq1cvODk5sbpCk+j9unz5Mm7evMkkSBcIBFi/fj2srKzg4+ODkpKS3/0ONiE6lyUlJTERGED9kVZtbW34+/sjPz+/yWsA9t2zJUuWiCWbbphTsaCgAHPnzoWJiYlY5FNoaKhE6kWgfsNSTU0NI0aMQF5eXnOL85f41O9+7tw5aGho4IcffhB7vyorK9G/f38xZ5skIHx/cnNzoaioKJZjcfjw4ejRowdkZWVhZWWFAQMGsFo3cnBwsAvO8fQv8OzZMzGjvKysDLq6uliyZIlYv4b5L9iutLdt2wZNTU3k5OQw+SKEE5Tw2J21tTVWrFjRnGL+aTZv3oy2bdsy5/ODgoKgpKTEVB+8ceMGpk6digEDBsDV1ZXVkWk9e/YUC3lOTExkEr8LKSkpwfDhw2FsbIykpCTG+XTs2DHWOz45JIehQ4fCxsaGeaZSU1MhJyeHmzdvAvif7igsLMS4ceMgLy/P5LgrKysTy1fDRj6VZLqurg7r169n8rK8e/euyf5sRVTO/fv3Y82aNYiIiGDuzcyZM2FjY4MFCxbg2bNnyMrKgpOTE8zNzVmtP0SdEaL5jgBg3rx5aNeuHbNoFAgEqKiowNWrV/H06VOJOR4TEBAATU1NaGlpQU1NDQEBAaisrIRAIEBYWBisra3h5+fXKPKJrZElos/inTt3YGJiAnNzc8ZJCNRvmujo6GDOnDlizie2Ym9vj+7duzO/+aFDh9CtWzexMQHAkydPMGnSJHTo0EEs15gk6cWGNu3OnTuhpaWFgIAAicshKTqu+Ph4rFy5EjNmzGAcvCtWrICKigqWLl2KU6dO4eLFixg2bBhMTU1Zrzeaev8FAgEqKyvh5eWFadOmMZX6gHpHaVpaGm7duiUxupGDg4MdcI6nf5jY2Fjo6+vDw8MDDx48YCbe77//Hg4ODvj1118hEAjA5/NZazgIaTgZeXt7w8/PD8D/DArRMbx8+RITJkzA9OnTWWvINoWnpyeTzPPQoUNQVlZmIn/Ky8tRU1PDJMIUjouNk+yKFStgbGzM3JOamhp07twZAwYMYI4yCamoqICenh769u2LrVu3ihmIbBwbh2Tx4MEDdOvWjYliysrKws8//4yRI0eiffv2uHXrFoD/6Y+DBw+Cx+OBx+Mx5ZoByVgQ79ixA76+vvD29mbyAvH5fKxduxZWVlaYOXMm43xi63iaQlilacKECRgyZAg6duyI2NhYlJWVYdGiRTA2NoaUlBS6d+8ulkic7RsoERERWLx4sVg1wcLCQlhaWmLTpk0QCARNJkVn43wt+jxlZmaiQ4cOuHDhAi5duoQ9e/agRYsWcHd3B1Avf1hYGAwNDREWFtZcIv8lFixYAFdXV1hbW0NNTQ1dunQRS9QfFxeH9u3bY/LkyXj+/HkzSvrb5Ofnw9TUlHn2Ll26hJycHIwfPx4DBw5EYmKiWP9z585BWVkZmpqaYjnH2KpHRN+RLVu2wNPTEx4eHli9ejXTvnXrVmhrayMgIABPnjxpDjH/FsKqnjNmzMCQIUOgo6PDRPqvWrUKVlZWkJGRgYmJCezs7CRGLwL1ucQ2b94s5mRKTEyEkpISrl+//snr2KgbOTg42AnnePqHqa6uxoYNGzBq1CgoKirC398fZ8+exbNnz6CoqIi9e/c2t4h/CFHD5tKlSwCAPn36YOrUqY36VFdXM1EMr1+/ZiYhNhpHDWXi8/kYO3Ysjh07hvPnz0NRUZFxOtXW1mLbtm1ISUlpMmkk25g/fz5MTU0B1O9879mzB4WFhejTpw8GDx6M06dPi/V3cXGBhoYGZs+ezdoxcUgmDx8+RKdOnbBq1Sp4enqid+/eKC0txa1btzBq1Choa2szOgOod0z5+Phg48aNEuX4DAwMhKamJtzc3ODi4gIejwcvLy9UVFSgrq4OoaGhsLGxwcSJE1FWVtbc4v5hDhw4AF1dXaZM/a5du6CgoIAff/wRQL1Tu6amBmfPnpWoROIAEBwcDHt7e6ioqCAoKAjnzp0DAPj5+cHOzq6ZpftrxMTEwMvLCwEBAWLtFy9ehLS0NONo4vP52L17t0QsgoXExsZCVVUV169fR0lJCYqKijBs2DD07dsXMTExTL8tW7bAxcWF1Yvg0tJSaGtrY8qUKZg1axbk5ORQV1eHmzdvYsKECbCxsRFzPmVnZ2P8+PGIjo6WqHsWHBwMdXV1zJkzByNHjkSnTp1gaWnJfB4dHY327dvD29tbLC8S20lNTYWuri4T5XTmzBnweDwxu76kpAS3b99Gfn6+ROnF8vJyzJ07F/Ly8hgxYgS+/fZb5rPJkyfD0dER5eXlzSghBwfHlwDnePoHaTi5xMTEMMn4hE6Bbt26oaioqJkk/GOIOiGWLFkCIyMjvHnzBqtWrUL37t2RmZkp1v/+/ftwc3NjohgAdu6AiMokmnfG398fysrKaNmyJbOwAupzJQ0aNEgsxwIbEd6vjIwMGBkZwdjYGMrKyrh//z4A4OnTpzA1NcXgwYOZ44MCgQDe3t44f/48qx2FHJJLUlISWrVqhVatWuH48eNMe25uLkaNGgUNDQ2kp6czzigfHx+mjyQY6pmZmdDS0hKLnDl9+jRatmwJf39/APXjWLx4MXx8fFipExsi1AGhoaEYPXo0gHonlJKSEuOQ//DhA3JychpdKwnjE/L27Vvs378fZmZm6NWrF6ZMmYKTJ09CRkZGLJJGEnj+/DmcnZ2hpKSEKVOmAKi/j8LjhIsXL4aVlVWj3E6S4shYsmQJ+vXrJxYlLoxQMzQ0FKse2VQkNlsQypSXlwdZWVkoKSnh2rVrzOe5ubmYOHEirKyssHr1aty7dw/Dhw8X2xiShHuWk5ODDh06MFHWAoEAFy9ehJGREWxtbZl+kZGRcHFxYbXd0VC27du3w8XFBQCwe/duKCsrY8uWLQDqcxM+ePDgk0ewJYX8/HwsWrQIXbt2hYGBASIiIrBkyRI4Ozs3ykXGwcHB8WfhHE9/gaYW6nw+v8kJ9N27d8jMzMTgwYPRpk0b9OvXj9UTrShXr17FiBEjmIXVhQsXYG1tDTc3N6YEutDo7devH6uNItHJPyQkBEOHDkV6ejqA+kXIiBEj0LZtW5SWluL9+/coKiqCg4MDrKysJGIRLMTe3h48Hg9OTk5i7U+fPkXfvn1hYWEBR0dHDBw4ED169BDLS8PB8U8g1G/R0dHg8XhQVFREaGgoCgsLmT737t3DlClTwOPxYGhoiN69e7O+5HnDdyQ9PR0GBgYoKSmBQCBgPk9NTYW8vDwuXLgAQHxuYOMiRPT3/vjxIwBg/fr1CAgIwMmTJ6GoqIitW7cyfZOTk7Fy5Uqx4xhsoyl9JnqPhBQVFeHUqVPo06cPunfvDh6Ph9mzZ38uMf8xMjIyMHbsWLRo0ULMyQsAa9asgaWlZZPHB9mM8LkMCQmBubk5KisrAfwvN+aZM2fQsmVLDB48GElJSY2uYyuJiYmQlZVFy5YtMX36dDH74vbt2wgMDISqqio6duwICwsL1uvFhvZwWloa1NTU8PLlS6ZPbW0t0tPT0bVrV2bzS/QaNurFpli+fDlcXFyQnZ0NJSUlsdxbMTExWLRoEaNDJZna2lpUVlZi7ty5cHFxgYqKCng8nliVRQ4ODo6/Aud4+otUVVVh2rRpuHz5spgxu2/fPrGwW+HEWlZWhuzsbFbvyIkSHx+P4cOHw87OTmwiPXToEIYPHw51dXUYGBigW7duMDU1ZXXCbVGCgoKgrq6OY8eO4dmzZwDqZc7KyoKZmRlUVVVhZGSEPn36iBl9kuCYETrQQkJC0K1bNya3h5CioiIsX74cHh4emDFjBmPwsv2ecUgmBQUFePfuHXbs2AElJSUsX75cbDEC1Du3RXUoW528whxNQH0VND6fj+zsbEhJSYk5mID64hIdOnTA4cOHxb6DrQtHIT/88AOio6MBAEeOHGFybonmlikrK8PQoUOZiC42U15ejhMnTjCFPoS/f1PRWkD93L18+XLWPoOAuK5uqLezsrIwduxYGBoaIi0tDTU1NSgtLYWdnR3rI0t+i1u3bkFaWhrLly8Xaz9+/DhcXV1hZ2eHIUOGNEoYz1Zu3LiBwsJCZGZmMlFqoveyrKwMBQUFuHTpEuuPaokmqT916hSAer2vr68vpjeAevtDQ0MDcXFxYu1sfy5XrlyJ4OBgAPXRQFpaWo30YmVlJZycnODj48P68fwRRMfw5MkTxMbGYsSIEax9Djk4OCQHzvH0Nxg8eDBsbW2ZcOkjR45ASkoKUVFRYv0aGoiS4MSIioqCnp4e1NTUGiUVfPz4Mc6ePYuIiAgcOHCA9YtGIefPn4eBgQGTvLiqqgpFRUVIT09HeXk56urqEBMTg507dyI1NVVixiWKMAH6rl270LVr10bOp4ZGkSSNjUNyiYyMZJxPnzpqzFa9eObMGbi4uODt27fw9/dHx44dUVxcjLKyMowfPx62tra4fPky0//t27fo2rUrDh061IxS/3mmTZuG9u3bM46asLAwSEtLIyYmBrm5ucjJycGwYcPQu3dvRm+weZGVkJAAJSUl7N27FxUVFQCAlJQU8Hg8xlkINP3csVEvitoR27dvh6enJ7y9vcWiLjIyMjBq1CjweDx07twZU6ZMgaWlZSPnm6QRGxsLWVlZBAYG4tq1a3j8+DGcnJywatUq3Lt3Dzwej3F8sInf+71PnDgBZWVlMedTU3ko2cjRo0fh6uqKX375BXPmzAGPx8OrV69QUlICZ2dnODk5iRU1KS0thampqcTkORUSGRkJIyMj5OXloba2FpGRkdDT08O8efNQUFCAc+fOwdHREcbGxhKhF/8onxoDG3UjBweH5MA5nv4CoobA2LFjMWTIEKxfvx6KiorYtWtXM0r21/jUBLNnzx506dIF7u7uuHPnzm/2Z+uiUZT09HTo6OigrKwM9+7dw6JFi2BgYABFRUWYm5s3aeBJwriaoqysDDExMejatSsmTZrEtEtCknQOyUF0sSR6bKKpdykyMhIqKioICQmRqISysbGxGDBgAIyMjKCmpiZWBvz48eMYOXIkevbsie3bt2Pv3r2wt7eHiYmJxOgO4b3Kz8+HlZUVk8uptLQUy5Ytg4qKCjQ1NZk8cZIUBRoeHg5DQ0P8/PPP2Lt3L1RUVJioLkklKCgIWlpamD17NmbOnIn27dsjMDCQ+fzSpUtwc3NDx44dsX37dqZdUiKCPsWBAwegqamJdu3aQUdHByYmJqisrERBQQE6deokVqyguWl4hKyuru6T6RhOnDgBFRUVTJs2TaLm5IyMDGhra6Nbt25QU1MTsxHv3r0LCwsL2NraIiAgAElJSbCzs4OxsbFE6A1Rrl+/DmNjYyQkJACoTy8RFRUFXV1dqKmpoVevXnBycpIovfhXkKRnk4ODg71wjqe/iGi+BGtra8jIyGDx4sXNKNFfQ3SB+OLFCzx58oTZHQXqS4Wbmppi+vTpuHv3bnOI+I+Rl5cHCwsLdOnSBRoaGvD29kZsbCyePn0KBQUFiduJ+z3KysoQGxuL7t27Y/jw4c0tDscXSlVVFSZPnoysrCwxo3vv3r2NyoNv2rQJPB5PrBoVWxE1tD08PMDj8TB06FCxXFVAfe67OXPmQFlZGX369GH9IuRTC4iqqiq4ublh6NChYu337t3DlStXcOfOHdYf/REiOq/t3LkTbdu2hYKCQqNoZEkjLi4OhoaGTLXB5ORkKCgooEWLFmLJ+c+dOwd3d3f07NmTqdr3JVBYWIhLly7hwoULzD1euHAhunbtyrqiLTU1NTAzM8OxY8eYv4H6SCHRimEAcPLkSfB4PKxateqzy/lnEd1k8Pb2hrS0NBwcHJhiJkLu37+P+fPno1u3brC0tMSoUaMkRi82dNLOmzcP7dq1YxL0CwQCVFRU4OrVq3j69KnE6EUODg6O5oZzPP1FhJPU8ePHoaSkBDMzMwwYMADXr1+XmJ0BUeN86dKlsLS0RIsWLeDh4SF2fj06OhpmZmaYMWMGU0ZWEhEIBMjKykJYWBiOHDnC5G0pLi6GpaWlWFj4l0JZWRmioqIwYcIE1obsc0g+Dg4O6N+/P3Pk7MiRI5CWlsamTZsAiOua/fv3s95Ab5hzZevWrQgPD8fgwYPh6uraaJEF1OuRDx8+MPqf7WNMSEiAv78/KioqGJkfPXoEZWVlsUiZhkiKHhH+/mfPnoW8vDw0NTVx8OBBsY0VttPwt960aRNCQkIA1L9jqqqqiIiIQEREBHg8nljkU1ZWFtzd3dGuXTucP3/+s8r9Obhz5w48PDzQpk0b3Lhxo7nFaZJvv/0W8vLyTELt/fv3o1WrVo3yHAHAlStXWK8zRJ9HgUCAAwcOID4+HgYGBnBzc2PSMgj1iTCh/5s3byRGL0ZERGDx4sVi1UqFVRQ3bdoEgUDQZKJ+SdGLHBwcHM0J53j6HUQn0IZthw4dgpycHBOCO378eAwcOBCXLl36/IL+DZYuXQoNDQ2kpKQgOzsbtra26NmzJ7NoBOojn9q1a4c1a9Y0o6S/z6fyIzTlDKyursbLly8xcuRIWFpasnIX7p+gsrJS4qrHcEgGos/ThAkTYGtri7CwsCaPHTd89ti6ABGVc/369diwYQMTTREXF4eBAwfC1dUVDx48YPqdOXOGySPU8DvYSEVFBfz9/dGzZ0/o6upi5cqVTBTN7NmzMWXKFJSWlrJ+HL/Hvn37oKSkhKSkJGzYsAGGhobYt28fUyFNUggNDWXyKT5+/BhFRUUwNjZGWFgYAODmzZto06YNeDweVq5cyVx34cIFeHl5iR0P/RKora1FTk4OAgICxI54sZHQ0FBIS0szx1a3bNnym/0lQS+uXbsWvr6+TGXL8+fPQ19fH25ubmJOwIZR5JKwKRscHAx7e3uoqKggKCiIiRj08/ODnZ1dM0vHwcHBIdlwjqffQDTctmGJ1NevX2PcuHHYuXOnWPvgwYPh5+f3WeT7J8jIyEDPnj2ZZKvnz5+HgoIC+vXrB2NjYybfBwAcPnxYYpwz8fHxePr06Sc/r6qqQnx8POzs7MRKTUvK+P4KkmD0cUgeoru//fv3h7S0NBYtWtSMEv0zBAYGom3btti4caPY8Tqh3nBycsKpU6dgb28PCwsLiXu/hLpu6dKlGD58OFRUVBAeHo6goCB89dVXrN9AEQgEv+kYy83NhZ6entjxuvDwcCgqKrI+ulV0XHFxcdDW1mYcg0D9PN2pUyemMuvdu3fh7u6O9PT0RnOYpDnZ/gxNRZ6wAeFxNOF99PDwgJSUFObOnQtAsu2MwMBAaGtrY8OGDXj48CHTfuHCBRgYGGDs2LFISEjAiBEjoK6u/sncVmzm7du32L9/P8zMzNCrVy9MmTIFJ0+ehIyMTCObn4ODg4Pjj8M5npqgYRnstWvXwtbWFuPGjUNsbCzTLpogV9SQkKRd4qKiImzYsAE1NTU4efIk2rRpg5iYGPz6668wMDBAly5dGuUdYLvRlJ+fDyMjI+a4YFPyCgQCpKWlISoqitlhZOtOIwcHW2io20QXFenp6VBSUoKFhQVsbGxw9epViVtwCDl06BC0tbWZiqWA+NiTk5Nhb28PXV1dDBw4kLUL4Ib3S7ggbnhfXr58ifj4eBgbG8PBwQE8Ho/VGyhlZWVif+/fvx8bNmxAWloa3r59C6B+fs7MzAQg/jskJSWxfg4TkpWVhblz5zIJ0YXjuHXrFlq3bo3vv/8ev/zyCxwdHTF+/Hjmvgqrm3J8Hn6rMElKSgqUlJQwZswYSEtL4/Tp02KfSxInT56Ejo4OMjIyxNqF47948SJsbGxgZmaGQYMGMXqRbc/ip2zChu1FRUU4deoU+vTpg+7du4PH42H27NmfS0wODg6OLw7O8dSA6OhodOzYEREREQCALVu2oHXr1li+fDlsbW1haWmJgIAApv+nHE5sdD59SqaPHz+ipqYGY8aMwZIlS5gxjR49Gj169IC/vz/rDIffY8yYMRg4cOAf7i+JRiAHR3OxfPlyJp8TUO+sl5OTY5y9EydORP/+/cXyZEgSUVFRzMLpUyWy37x5g7y8PNYnlq2qqkJqaioTwSuU89GjRygtLRXrW1BQgLS0NPj5+bF2PAsXLsT48eMZ2efPnw9NTU0YGhoyVVgLCgoAiN+zhjqezTqfz+cjNzcXCgoKkJGRwdq1a5nPBAIBPnz4gJCQEKiqqkJPTw9mZmasXeT/lwgLC0NSUhLz94EDB6CkpMREjq9duxby8vI4evRoc4n4t4iOjoalpWWT1XGF71NRURGePXvGer1YXl6OEydOMDnfhOPIyclpsv++ffuwfPly1o6Hg4ODQxKQIg4x7O3tycHBgfbt20dr1qyhgoIC2r17Ny1btowOHTpEjo6OdO7cOQoMDCQiImlpaeLz+UREJCX1v59T9N9sQCAQMDJdvnyZjh07Rjdv3qS3b9+SoqIiEREVFBQQn88naWlpqqmpIQUFBfr222/phx9+IB6PRwCacwhNIhAIxP4W3otVq1bR8+fPKSkp6Q99j7S09D8uGwfHl4Lou797927asGEDVVVVERHRu3fvaM+ePbRlyxby9PRk+rRq1YoSEhKaRd6/y4sXL+jRo0ckKytLMjIyxOfzicfjEZ/Pp3PnztHr169JXV2dunbtSlJSUiQQCEhGRqa5xW6SnTt3UlRUFP34449UVVVFMjIytHfvXjI3N6fCwkKmHwDq0KEDOTo60pYtW0hGRoZqa2ubUfLGACBZWVkqLCykRYsW0eXLl+nRo0eUnp5Od+7coQULFtCLFy/I39+fnj9/Tjwej5kjGup4tul80XdMSkqKevXqRXFxcdS6dWs6e/Ys3bt3j4iIeDweKSkp0dy5c+nq1asUGxtLly9fJllZWaqrqyMej9dcQ/jPIWp/xMbG0g8//ECGhobE5/OJz+dTUlISrV27lmbMmEFEREFBQRQYGEhr164lImKlTfVbCAQCev36Nb1+/Vqsva6ujpKTk6mkpITatm1Lurq6rNeLBw8epLFjx9Lhw4epsrKSeDwepaamkpmZGWVkZDD9hDbluHHjaNmyZSQjI0N1dXXNJTYHBweHRMODpM18/yJC58yLFy9o5cqVdPv2bXr58iUdPHiQTExMiIiotLSUNm3aRD/99BMNGjSIwsLCmlnq3wcAY4wuWrSI9u7dS61atSI+n0+dO3em4OBgMjMzIx8fH3r+/DkZGxvT7du3qaSkhK5du8YYEGxzpomO69ChQzRkyBCSk5MjOTk5Ki4uJm9vb9LS0qKtW7eK9eXg4PhrnDp1io4dO0a9e/emKVOmMO3FxcWkrq5ORMQ4r4mIlXpDlE/Jl5WVRZ6enjR9+nSaO3cuycvLE1G9/h87dix5e3vThAkTPre4f4mKigpas2YN5eXl0cSJE6m2tpZ8fX1pxYoVNHv27OYW7w8j1OECgYAiIiLo6NGjpKqqSlJSUpScnExycnJERJSYmEi7du0iVVVV2rRpE+nq6rJe/4vKl5ycTK9evaI5c+YQUb0TNygoiMaOHUuzZ88mQ0PDRtcQib93HJ+X7Oxs2rt3L3Xv3p28vb0ZvVJXV9ek44Xtz+On9OL58+dp3LhxtGTJEvL09KTWrVsTEVFVVRUNGzaMRo8eTfPmzfvc4v5lIiIiaOvWrRQdHU3FxcXk4+NDYWFh5OPj09yicXBwcHyZfP4gK3bS8Bja8+fPMXPmTCgpKTVKlFtSUoLvv/8eurq6YpXf2M7mzZvRtm1b5nx+UFAQlJSUmFK/N27cwNSpUzFgwAC4uroyoftsPzaYn58PdXV19O7dG97e3sjLywPwv0TpDfMRcHBw/HkyMzNhbGwMNTU1JCcnA/j0MQq2HzsGxOXav38/1qxZg4iICGRlZQEAZs6cCRsbGyxYsADPnj1DVlYWnJycYG5uLjHHLYRjLCsrQ1hYGPr27QsFBQVs3rxZ7HNJQSgvn8/HmjVrYGRkBD09vUYJtBMTE2FnZwcbGxu8evWqOUT9w4jegzt37sDExATm5uZMtVygPsG4jo4O5syZg/z8/OYQk6MJBAIBcnJyIC8vDzk5OSZFA/D77xZbj0SKyh0fH4+VK1dixowZyM3NBQCsWLECKioqWLp0KU6dOoWLFy9i2LBhMDU1lTi9CAA7d+5E27ZtoaCgIFaIgIODg4Pjn4dzPEF8EkpMTGQq3hQVFWHmzJkwNzdHeHi42DXFxcWIiYlhdZ6Ihnh6emLZsmUA6pPnKisrM7kHysvLUVNTg7q6OrHEpGw0JDIyMpgyvt999x3WrFmDiooKhIeHw9nZGa1atcKsWbMQFxcHLy8vBAUFgc/nS9wii4ODTdTW1iI0NBS6uroYMmQIk2NH0t8rYZWmCRMmYMiQIejYsSNiY2NRVlaGRYsWwdjYGFJSUujevbtYInFJ0f1CHZ6UlAR5eXmYmZkhLi6OyfkkCfevKRn5fD4iIiLQqVMnTJs2DcXFxWKfb9u2Dd98841EjA8AFixYAFdXV1hbW0NNTQ1dunQRq6AVFxeH9u3bY/LkyXj+/HkzSsrRkMTERKipqWHEiBHMxpekI6zqOWPGDAwZMgQ6OjqMHbxq1SpYWVlBRkYGJiYmsLOzk1i9ePbsWcjLy0NTUxMHDx5kcj5xcHBwcPzzcI4nEQIDA6GlpYXIyEjGiH3+/Dn8/PxgaWnZyPkkhI0TbcPdND6fj7Fjx+LYsWM4f/48FBUVGadTbW0ttm3bhpSUlCaTRrKJ4uJiKCkpYeTIkZgxYwaUlZVx8+ZNsT6JiYnw8/ODpqYmeDweOnTowDiq2DgmDg620VT1OqBe161fvx4mJibw8/PDu3fvmuwvKRw4cAC6urpMqfpdu3ZBQUEBP/74I4D6cu01NTU4e/asRCQS/xR79+6FqqoqNm3ahGXLlmHcuHHYtWuXRCyyRJ+ty5cv4+bNm0z0hUAgwPr162FlZQUfHx+UlJT87newkdjYWKiqquL69esoKSlBUVERhg0bhr59+yImJobpt2XLFri4uLB+PF8qor97Q7tv586d0NLSQkBAAB4/fvy5RftHSU1Nha6uLvOenTlzBjweD3v37mX6lJSU4Pbt28jPz5dYvbhv3z4oKSkhKSkJGzZsgKGhIfbt29cogpKDg4OD45+Bczz9P9u2bYOmpiZycnKYnWChk0J47M7a2horVqxoTjH/EKLG0cOHD5l/+/v7Q1lZGS1btmQWVkC9M2fQoEFYt27dZ5Xzz3D69GlmR62wsBAKCgpQVFTEhQsXAIiXdQeA6upqPH78GIGBgdDX10dwcHCzyM3BIWmI6o8dO3bA19cX3t7eTMU6Pp+PtWvXwsrKCjNnzmScT5Lk1BXKGhoaitGjRwNoXIHqw4cPTVY4YtuiXyAQ/KZMt2/fZpxOAFBZWYmlS5fCzs4OP/300+cS828TEBAATU1NaGlpQU1NDQEBAaisrIRAIEBYWBisra3h5+fXKPJJEp7LJUuWoF+/fmKRuYWFhbC0tIShoSFiY2OZvkKHB9uewy8d0d97y5Yt8PT0hIeHB1avXs20b926Fdra2ggICMCTJ0+aQ8y/RMN3ZPv27XBxcQEA7N69G8rKytiyZQsA4P3793jw4MEnNyfYwu/pxdzcXOjp6YkdrwsPD4eioiJz6oGDg4OD45/lP+t4ajjRent7w8/PD0DTht3Lly8xYcIETJ8+ndWGrKjMISEhGDp0KNLT0wEAb9++xYgRI9C2bVuUlpbi/fv3KCoqgoODA6ysrFi7W7V69WpYWloyhsSdO3fA4/GgoqKCMWPGiC00RHOAAPWLrG+//RbDhg1j7fg4ONhIYGAgNDU14ebmBhcXF/B4PHh5eaGiogJ1dXUIDQ2FjY0NJk6ciLKysuYW93cR1dsfP34EAKxfvx4BAQE4efIkFBUVsXXrVqZvcnIyVq5cyURLSgIpKSlISkrCkSNHmLYHDx4wEV1CvVheXo7t27ezbrEoiuj9yszMRIcOHXDhwgVcunQJe/bsQYsWLeDu7g6gflxhYWEwNDREWFhYc4n8pxGOMSQkBObm5kykhXCT5cyZM2jZsiUGDx6MpKSkRtdxfH6Cg4Ohrq6OOXPmYOTIkejUqRMsLS2Zz6Ojo9G+fXt4e3vjxYsXzSjpX2f58uVwcXFBdnY2lJSUmJxwABATE4NFixYxOpSNNJyP9u/fjw0bNiAtLQ1v374FALx48QKZmZkAxO3mpKQkVp5i4ODg4PgS+E86nkSNtkuXLgEA+vTpg6lTpzbqU11dzRzlev36NTNBsd3wCwoKgrq6Oo4dO4Znz54BqJ9cs7KyYGZmBlVVVRgZGaFPnz6wsLBg/fl8odPozp07AOrlfPjwITQ0NODs7MwYE02Rm5sLDQ2NLyb3AgfHv01mZia0tLRw8eJFpu306dNo2bIl/P39AdS/k4sXL4aPjw+rHRgN+eGHHxAdHQ0AOHLkCHg8Hng8HhPRBdQvXIYOHcqMlY14enrCx8eH+Xvu3LlQU1ODgYEBdHR04OXlxXz2W0eE2H7vYmJi4OXlhYCAALH2ixcvQlpamnE08fl87N69m7Vz2G9x69YtSEtLY/ny5WLtx48fh6urK+zs7DBkyBAmGpujecjJyUGHDh2YiBiBQICLFy/CyMgItra2TL/IyEi4uLiw3k4UZeXKlUxkeH5+PrS0tBrpxcrKSjg5OcHHx4e1Y1u4cCHGjx/P5CCcP38+NDU1YWhoiC5dusDd3R0FBQUAxO34hnpDEvUIBwcHB9v5zzmeRCeaJUuWwMjICG/evMGqVavQvXt3ZgdEyP379+Hm5oZbt24xbWw31M+fPw8DAwNcuXIFAFBVVYWioiKkp6ejvLwcdXV1iImJwc6dO5GamspMsGyMCBLNQZKWlgYej4c9e/agvLwcQL0hqKmpidGjR+PVq1fg8/nw8PAQqza4Zs0a6OjosL66EQdHc9HQyE5PT4eBgQFKSkogEAiYz1NTUyEvL9/kEVe260Uh06ZNQ/v27RndEhYWBmlpacTExCA3Nxc5OTkYNmwYevfuzehEti2yysvLsXbtWqirqyM4OBgfP35E//79cfv2bTx58gRJSUlQUVHBhAkTmGskcSH1/PlzODs7Q0lJCVOmTAFQfy+EDpjFixfDysqqUW4nSRxrbGwsZGVlERgYiGvXruHx48dwcnLCqlWrcO/ePfB4PJw6daq5xfxP0XCjMS0tDWpqanj58iXTp7a2Funp6ejatStTIVj0GknRi5GRkTAyMkJeXh5qa2sRGRkJPT09zJs3DwUFBTh37hwcHR1hbGzMWr0oEAjw3XffwdraGr6+vsjOzoazszOuX7+Oqqoq7NixA7a2tnB2dhbbkOXg4ODg+Dz85xxPQq5evYoRI0YwO/oXLlyAtbU13NzccPbsWQD/M3r79esnUYZseno6dHR0UFZWhnv37mHRokUwMDCAoqIizM3Nm5xo2Tg+UTkfPHgAAJgyZQpUVFSQnJzMHEu4ceMGNDU1YWRkBBMTE3Tp0oWJ4ALqQ+Nv3LjxWWXn4JAUhDmaAOD69evg8/nIzs6GlJSUmIMJAJ49e4YOHTrg8OHDYt/BtgVIUwjHkJ+fDysrKyaXU2lpKZYtWwYVFRVoamrC1NQUgwcPZn0UaGlpKTZv3ow2bdrAxcUFHh4ejDOturoaKSkpUFFRYY6jAZK5yMrIyMDYsWPRokULHD9+XOyzNWvWwNLSUkzfSzIHDhyApqYm2rVrBx0dHZiYmKCyshIFBQXo1KlTo0IaHP8eokf4hQ6/goIC6Ovri0UBAfUVkDU0NBAXFyfWLgl6Ucj169dhbGyMhIQEAPX2b1RUFHR1daGmpoZevXrBycmJtXpR1NG3bt06DBw4EC4uLhg9erRYpGBCQgLzmdD5JEn3iYODg0OS+U86nuLj4zF8+HDY2dmJnVM/dOgQhg8fDnV1dRgYGKBbt24wNTVlJlpJMdrz8vJgYWGBLl26QENDA97e3oiNjcXTp0+hoKAgVpmErRw/fhyTJ08GAMyePRu2trbMffDy8kKrVq3EnE+//vorAgMDsXLlSmY3jjuWwMHx25w5cwYuLi54+/Yt/P390bFjRxQXF6OsrAzjx4+Hra0tLl++zPR/+/YtunbtikOHDjWj1H+MTy0mqqqq4ObmhqFDh4q137t3D1euXMGdO3dYXaVJdB56//49szg0MTER61ddXY3U1FSoqanB0dHxc4v5pxEdV8O5NisrC2PHjoWhoSHS0tJQU1OD0tJS2NnZSdyRpt+jsLAQly5dwoULF5jfYeHChejatSuKioqaWbr/BkePHoWrqyt++eUXzJkzBzweD69evUJJSQmcnZ3h5OQkloC6tLQUpqamEmFbNSzCIsq8efPQrl07JoJQIBCgoqICV69exdOnT1mtFwHxHJ9r1qyBkZER9PT0GlWpS0xMhJ2dHWxsbLhIeA4ODo7PyH/S8RQVFQU9PT2oqanh+vXrYp89fvwYZ8+eRUREBA4cOMDqY2ifQiAQICsrC2FhYThy5AgT0VBcXAxLS0vWV+yoqanBDz/8gO7du8PU1BSqqqpMxJMQb29vtGzZEsnJyUwiSVGDSpLuFwdHcxEbG4sBAwbAyMgIampqYmXAjx8/jpEjR6Jnz57Yvn079u7dC3t7e5iYmLBut/u3SEhIgL+/PyoqKhgd8ejRIygrK2P79u2fvI6NGw2iMt2/fx/l5eUoLy/H5s2bIS8vj/nz54v1r66uxp49ezBs2DBWjkeIqGzbt2+Hp6cnvL29xZIaZ2RkYNSoUeDxeOjcuTOmTJkCS0tLJsrrS3I+Cblz5w48PDzQpk0bLmr3M5KRkQFtbW1069YNampqTG5JALh79y4sLCxga2uLgIAAJCUlwc7ODsbGxhKlFyMiIrB48WKxPH7CSoqbNm2CQCBoMpKQjXqkKZn4fD4iIiLQqVMnTJs2rVG1y23btuGbb75h5Xg4ODg4vlS+eMfTp4zRPXv2MIkGRY2Kpvqz0ZhoKOdvJT2vrq7Gy5cvMXLkSFhaWrJyPA0RCARwdHQEj8fDmDFjmHbRnE/e3t5QVlZGTEwMF93EwfEnENUTHh4e4PF4GDp0KAoLC8X6XbhwAXPmzIGysjL69OnD6qMWTVFRUQF/f3/07NkTurq6WLlyJVPhbfbs2ZgyZQpKS0slYvEhKuOSJUswZMgQpKSkQCAQoLS0FFFRUWjdujUCAwPFrhN1wrN9nEFBQdDS0sLs2bMxc+ZMtG/fXmw8ly5dgpubGzp27CjmNPwS9X9tbS1ycnIQEBAgZqNw/HsIBAJGN3p7e0NaWhoODg64f/++WL/79+9j/vz56NatGywtLTFq1CiJ0otAfQoCe3t7qKioICgoCOfOnQMA+Pn5wc7Orpml++OI6rTLly/j5s2byM3NBVB/P9evXw8rKyv4+Pg0ygXX1HdwcHBwcPx7fNGOJ9HJ5MWLF3jy5ImY42LHjh0wNTXF9OnTcffu3eYQ8W8THx+Pp0+ffvLzqqoqxMfHw87OTiwXBhuNI6HBV1dXh48fPyI0NBSLFi2Cqakppk2bxvQTJhYHADc3NwwaNOizy8rBIamI6sWysjJs3boV4eHhGDx4MFxdXRstsoD6aMkPHz4w76gkRRQKdd3SpUsxfPhwqKioIDw8HEFBQfjqq6+YyqaSwtKlS6Guro6jR4+K7eILnU9t2rRhqlNJEnFxcTA0NGQcg8nJyVBQUECLFi3EqvedO3cO7u7u6NmzJ7NY/pL5UvJXsR1RvSgQCHDgwAHEx8fDwMAAbm5uTHS8UAcKiy68efNGIvUiUH90ev/+/TAzM0OvXr0wZcoUnDx5EjIyMti5c2dzi/enCAgIgKamJrS0tKCmpoaAgABUVlZCIBAgLCwM1tbW8PPzaxT59CVGSnJwcHCwlS/W8SRqRCxduhSWlpZo0aIFPDw8xBJDRkdHw8zMDDNmzGB2SSSF/Px8GBkZMeNpypkkEAiQlpaGqKgoxihio3H0qR2n8vJyREZGwtjYWMz5xOfzcfv27d+8loODQxzRd2X9+vXYsGEDkzcmLi4OAwcOhKurq9jR1jNnzqCioqLJ72ALDWUSRi40XFS8fPkS8fHxMDY2hoODA3g8Hvz8/D6nqH+LBw8eoEePHvjpp5/E2oXjfPfuHTZv3gwejyd2TI2NNLxnmzZtQkhICADgyJEjUFVVRUREBCIiIsDj8cQin7KysuDu7o527drh/Pnzn1Vuji8P0Wdx7dq18PX1xfv37wHUVwnW19eHm5ub2HHHhvmc2OjA+JRN2LC9qKgIp06dQp8+fdC9e3fweDzMnj37c4n5lxD9vTMzM9GhQwdcuHABly5dwp49e9CiRQumsAKfz0dYWBgMDQ0RFhbWXCJzcHBw/Of5Yh1PQpYuXQoNDQ2kpKQgOzsbtra26NmzJzZt2sT02bFjB9q1a4c1a9Y0o6R/jTFjxmDgwIF/uD8bI51EWbduHcaNGwdXV1cm98D79++xceNGmJiYYNKkSXj16hWGDh0qdgSPjYthDg62EhgYiLZt22Ljxo1ix+uE0ZFOTk44deoU7O3tYWFhwcpFVUOqqqqQmprKHLsSOtgfPXqE0tJSsb4FBQVIS0uDn58fKx3xQhrqtXv37kFTUxPXrl1r1LeqqgofP35EeXk5Dhw4wOpxiRIaGsrkU3z8+DGKiopgbGzMLBBv3ryJNm3agMfjYeXKlcx1Fy5cgJeXl1heMg6Ov0NgYCC0tbWxYcMGPHz4kGm/cOECDAwMMHbsWCQkJGDEiBFQV1cHn89nvW4sLy/HiRMnGuVCy8nJabL/vn37sHz5conRHzExMfDy8kJAQIBY+8WLFyEtLc3oET6fj927d7PeBubg4OD4kvmiHU8ZGRno2bMnUxL8/PnzUFBQQL9+/WBsbMyU0waAw4cPs3pCargAEcqal5eHjh07Ys+ePc0h1t9GdFwrVqxgqvANGjQIUlJSSEpKAlDvfNq+fTs6d+4MbW1tWFhYcEcQODj+AocOHYK2traY80L0PUxOToa9vT10dXUxcOBAiXnPoqKiMHjwYOzatYupYpScnAxVVVUmOhJoOjKB7WP08fFBbGwsnjx5Ajk5ORw8eBBA/TwgHE9GRgbi4+PF5jE2Lh5Fn7W4uDhoa2szx+uA+nm6U6dOTKnzu3fvwt3dHenp6Y3m6IbVqjg4/ionT56Ejo4OMjIyxNqFz+vFixdhY2MDMzMzDBo0iNEZbHc8JSQkQElJCXv37mUiV1NSUsDj8RjbGGh6U5KN+kOU58+fw9nZGUpKSpgyZQqA+vsh3HxYvHgxrKysGuV2YrOtz8HBwfElI0NfMIaGhjRt2jSysrKiU6dO0YQJE2jLli00fPhwsrGxoQ0bNtDbt29p8eLF5OzsTEREfD6fpKWlm1lycQCQlJQUEREdOnSIhgwZQnJyciQtLU3q6urUs2dPunDhAk2YMIEAEI/Ha2aJ/zjCcb148YKIiFJSUqhfv35UWVlJK1asIA8PDxIIBDRx4kTy9PSkESNG0L1798jW1pakpaWprq6OZGS+6MeYg+MfpbCwkLp06ULGxsbM+yOqM77++msaPHgwFRcXU+fOnUlKSkoi3rOpU6fSq1evKD09nVq3bk21tbXk5+dHISEh1KNHD6ZfU/pRVlb2c4r6u4jq8fPnz1NKSgqNGTOG9PX1aerUqTR//nxSV1enAQMGEBFRbW0thYSEkKGhIXl6ejLfw8Z7JtT5ly5dotzcXFq2bBlZWlqSQCAgKSkpat26NRUXF1N8fDxNmjSJFixYQEpKSmRvb088Ho/4fD5JSUkRj8cjBQWFZh4Nx5fCL7/8Qu3atSMrKyumTWh78fl8sra2pgMHDlBtbS3p6OhIjF708PCgN2/e0JIlS0hdXZ2Ki4vJx8eHtm3bRv3792f6NWX3sn1s7dq1o8DAQJKTk6O9e/eSm5sb2dvbk5ycHBERKSsrEwBSVFQUu45tNj4HBwfHfwV2zyp/AqHRKkrbtm3J29ubiIi2bdtGvr6+5OnpSdLS0mRsbEz5+fn06tUrMSOfbROS6LgePXpE06dPp3bt2pG5uTkFBARQ165daf78+WRvb0/u7u7Ur1+/Zpb4z3PkyBEaNWoU6enpkYODAxERtWjRgr7//nsiIpoyZQpJSUmRm5sbaWlpkZaWFhHVOwnZbhhxcLCNFy9e0KNHjxhni9DZzufzKSMjg7p160aampqkrq5ORPU6iO3vmUAgoJYtW1JwcDBt2bKF1q1bRzdu3KDw8HCaOXNmk/MDmxHOR4mJiXT9+nWaO3cu2dvbExGRl5cXffjwgVxcXMjf358EAgFlZWXRmzdvKC0trTnF/kMIBAK6ffs22dnZUV1dHa1atYqI6h1SAEhPT4/mzZtH4eHhtGvXLmrTpg0dPnyYeDweAWDdHM3xZSAQCOj169f0+vVr0tbWZtrr6upo79695OjoSG3bthXrLwl6UUpKiubPn08qKirk7u5O7969o/Xr15OPj09zi/enENXhov/u168foxNmzZpFGzdupCFDhlB5eTmdPHmS2rZty/r7xMHBwfFfQXIs8d9AdBK6fPkyHTt2jG7evElv375ldjoKCgqYBVZNTQ0pKCjQt99+Sz/88ANj0LKNzMxMKisrIyKipUuX0sGDB+nZs2fk4eFBr1+/JnNzc5o9ezb98ssv5O7uTj/99BMJBAISCATNLPmfo0+fPuTr60vPnj2joqIiIqq/p7KysrRy5UoKDAykiRMn0s8//yx2HbcA4eD4NJ/SAyNGjCA5OTlau3YtVVdXM+/Rhw8f6Pvvv2/0nkmCw0YYfdCqVSvS1dWlnJwc6t69O7Vq1YpqampISkpK4vTikydPKC4ujnbs2EEfP35k2vv06UOrVq2ihQsX0qFDh+jKlSvUsWNHysnJIRkZGaqrq2tGqZtGdH6VkpKiXr16UVxcHLVu3ZrOnj1L9+7dI6J6h5uSkhLNnTuXrl69SrGxsXT58mWSlZWluro6iYrm5WAnn9IDRkZGVFZWRvv376fS0lIiqn8e6+rqKDo6muLj48X6S5JeJCIyMDCg0tJSUlZWJi0tLaqurm5m6f44ojb+jh07aOrUqTR9+nTasmULERH17duX5syZQz169CAnJyfq0aMHzZs3j8rLy2nv3r2stfE5ODg4/mvwIOHaWDRaadGiRbR3715q1aoV8fl86ty5MwUHB5OZmRn5+PjQ8+fPydjYmG7fvk0lJSV07do1ZkHCNiPi7du3pK+vT7a2tqStrU1JSUmUkZFBxsbGTJ8ff/yRsrKy6ODBg/TmzRtq37493bp1iwkvZqOR/qnf+v379zRz5kw6dOgQnTp1iqytrZkx1NbW0q5du8jb25vbueLg+AOIvmcHDhygx48fk5ycHFlZWVHfvn3pm2++oZs3b1Lfvn3J39+fCgsLadWqVfTq1Su6dOmSxL5n+/btoxkzZtD3339PxcXFdO/ePXJwcCB3d3eSl5dvbvH+NMePH6eIiAi6ceMGnTx5kkxMTMQ+r6yspBYtWjB/s/Hoj+hclJycTK9evaI5c+YQEdHu3bspKCiIxo4dS7NnzyZDQ8NG1xCx8wg8h+QhqhcTEhLo+fPn9Pz5c/Lz86NevXpRSEgIRURE0Jw5c6h///7UsmVLWrFiBRUXF9Ply5dZ9279Ufbv309eXl60fft2+vXXX2nz5s20evVqGjlypEQdVw0ODqbExEQaO3Ys8fl8Onr0KH399dcUFhZGRETZ2dkUGRlJV65coYULF9L06dOJiKimpoY5fsfBwcHB0Yx87qRS/xabN29G27ZtmcSQQUFBUFJSwsmTJwEAN27cwNSpUzFgwAC4uroyiSHZVg3t9OnTjGyFhYVQUFCAoqIikwSyYRWV6upqPH78GIGBgdDX10dwcHCzyP1HEP2tY2NjERwcjFmzZiElJQVAfaJYd3d3tGrViqlo1zBxJ9uTXXJwsAlhlaYJEyZgyJAh6NixI2JjY1FWVoZFixbB2NgYUlJS6N69u1gicTYmXxUIBL+pr2/fvg1VVVWmYmllZSWWLl0KOzs7/PTTT59LzL/Eb43r1KlTcHBwgLm5OXJzcwH8L6m46HVsTHIsKt+dO3dgYmICc3NzJCQkMO1xcXHQ0dHBnDlzkJ+f3xxicvzHEFb1nDFjBoYMGQIdHR2Eh4cDAFatWgUrKyvIyMjAxMQEdnZ2Eq0Xc3Nzoaenh6ioKKYtPDwcioqK+Pnnnz+HiP8IcXFxMDQ0ZAoRJCcnQ0FBAS1atICPjw/T79y5c3B3d0fPnj1x7ty55hKXg4ODg6MJvhjHk6enJ5YtWwagvmqTsrIyU7WuvLwcNTU1qKurE6sCxDYnxurVq2FpackYEnfu3AGPx4OKigrGjBmD4uJipq/Q0BD+v7KyEt9++y2GDRvGunE1JDAwEF999RXmz5+PcePGoWPHjpg/fz4A4PXr1/Dw8ICysjLOnj3bvIJycEgwBw4cgK6uLmOo79q1CwoKCvjxxx8B1Fdyq6mpwdmzZ5GXl8foErbrD6C+KlNSUhKOHDnCtD148IAZq3As5eXl2L59O+s2GERpWOXNz88PCxYsYCp6AkBaWhpGjBgBCwsL3Lx5EwA7HU2fYsGCBXB1dYW1tTXU1NTQpUsX7Ny5k/k8Li4O7du3x+TJk/H8+fNmlJTjSyc1NRW6urqME/fMmTPg8XjYu3cv06ekpAS3b99Gfn4+q/ViWVmZ2N/79+/Hhg0bkJaWhrdv3wIAXrx4gczMTADiuiYpKYmVjjQhDXX2pk2bEBISAgA4cuQIVFVVERERgYiICPB4PAQGBjJ9s7Ky4O7ujnbt2uH8+fOfVW4ODg4Ojk8jkY6nhgY3n8/H2LFjcezYMZw/fx6KioqM06m2thbbtm1DSkqKmOHAVqNdKOOdO3cA1O+wPXz4EBoaGnB2dmaMiabIzc2FhoYG8vLyPousf4X09HTo6+vj8uXLAIB9+/ZBQUFBbAf83bt3cHR0xODBg5tLTA4OiUWo20JDQzF69GgA9U4oJSUlRi9++PABOTk5ja5lo4PG09NTbEd77ty5UFNTg4GBAXR0dODl5cV8Jip/w0UVG8cmSlBQELS1teHp6QlPT0+0a9cO69evZz5PT0+Hs7Mz9PT08OjRo2aU9M8RGxsLVVVVXL9+HSUlJSgqKsKwYcPQt29fxMTEMP22bNkCFxcX1t8nDsmioa23fft2uLi4AAB2794NZWVlbNmyBQDw/v17PHjwoNEzyMZncuHChRg/fjxKS0sBAPPnz4empiYMDQ3RpUsXuLu7o6CgAID4b9BQL7LZ+QTUz2MHDhxAXV0dHj9+jKKiIhgbGyMsLAwAcPPmTbRp0wY8Hg8rV65krrtw4QK8vLzw+PHj5hKdg4ODg6MB7Eps9AcQCARM7of8/Hwiqk+gqK2tTRMmTCBHR0fatm0bzZgxg4jqcwft3buXHj9+LHY+n235j4SJHmVkZCg9PZ169uxJSUlJVF1dTZ06daITJ05QdnY2eXt70+vXr0kgEJCnpydFRUUx33H8+HGSk5MjNTW15hrG7/Ly5UvS1dUlCwsLOnDgAHl5edGGDRvIw8ODysrKKDMzk1RUVCg5OZlOnjzZ3OJycEgEEEnVV15eTkREsrKy1LFjRzp16hRNmTKFwsLCaMaMGQSA0tLSKC0tjT58+CD2PWzLdVdRUUHdu3enlJQUWrhwIZWVldH169fp/PnzdOrUKVq/fj0dOHCAJk6cSETElD4nalx8gG1jEyUmJoYOHDhAKSkpFB8fT0OHDqVXr17RkiVLaNmyZURE5ODgQFOnTqVx48aRnp5e8wr8J3j06BH16NGDevfuTSoqKtS2bVuKiYkhgUBAq1evpri4OCIi8vPzo4MHD0pkIngO9tLQ1nv58iUR1Rei8fX1pdDQUPLz8yMiooMHD1JcXBxVVFSIXcM23QGAZGVlqbCwkBYtWkSXL1+mR48eUXp6Ot25c4cWLFhAL168IH9/f3r+/DnxeDzmnWqoF9mWO0303Y+Pj6dNmzZRu3btSFpamjp27EgPHz6kyspKcnNzI6J6m9nBwYHS0tJo4cKFzLX9+/enqKgo6tix42cfAwcHBwfHJ2hmx9efQnTXKSQkBEOHDkV6ejoA4O3btxgxYgTatm2L0tJSvH//HkVFRXBwcICVlRUrw6SFiI7rwYMHAIApU6ZARUUFycnJqKysBFCfp0pTUxNGRkYwMTFBly5dmNwDABAcHIwbN258Vtn/LPHx8XB3d0daWhoUFRWxdetW5rPU1FQEBgbizZs3TBsbdxo5ONjKDz/8gOjoaAD1xxF4PB54PB7i4+OZPmVlZRg6dCj8/f2bS8w/RWlpKTZv3ow2bdrAxcUFHh4eqKqqAlCf4y4lJQUqKipwd3dnrpEkvVFbW4ulS5cyO/hHjhyBiooK1q1bh2+//RZSUlJM/hlR2B6pIIyyCAkJgbm5OTOPCeesM2fOoGXLlhg8eLDYsUK2RiNzSC4rV65k8l/m5+dDS0urkV6srKyEk5MTfHx8WP0MCmXj8/lYt24dBg4cCBcXF4wePRrV1dVMv4SEBOazZ8+eiV0rCWRlZWHu3LnMfCbU6bdu3ULr1q3x/fff45dffoGjoyPGjx/PjE00nQYHBwcHB7uQKMeTkKCgIKirq+PYsWPMhMrn85GVlQUzMzOoqqrCyMgIffr0gYWFBasTQx4/fhyTJ08GAMyePRu2traMvF5eXmjVqpWY8+nXX39FYGAgVq5cyTjTRI0NtpOXlwc5OTnweDzExsYy7RUVFbC3t4eXlxdnNHBw/EWmTZuG9u3bM46ZsLAwSEtLIyYmBrm5ucjJycGwYcPQu3dvRn+w9X0TdR69f/8eUVFR0NXVhYmJiVi/6upqpKamQk1NDY6Ojp9bzD9NU793aWkp8vPz8ezZMxgZGTGOpoyMDLRs2RI8Hk/MSS9J3Lp1C9LS0li+fLlY+/Hjx+Hq6go7OzsMGTJEouYxDskiMjISRkZGyMvLQ21tLSIjI6Gnp4d58+ahoKAA586dg6OjI4yNjVmvFwHxHJ9r1qyBkZER9PT0GDtRSGJiIuzs7GBjY4NXr141h6h/Gj6fj9zcXCgoKEBGRgZr165lPhMIBPjw4QNCQkKgqqoKPT09mJmZMTYzm+8ZBwcHB4cEOp7Onz8PAwMDXLlyBQBQVVWFoqIipKeno7y8HHV1dYiJicHOnTuRmprKOJvYGPFUU1ODH374Ad27d4epqSlUVVWZiCch3t7eaNmyJZKTk5lEkqKTKxvH9Xvs378fLVq0QFBQEM6ePYszZ85g6NChEmP0cXCwDeFCJD8/H1ZWVkwup9LSUixbtgwqKirQ1NSEqakpBg8ezGpnPCDudLp//z7Ky8tRXl6OzZs3Q15enilGIKS6uhp79uzBsGHDWB3t1NCZVllZifLycqYtLS0NPXr0YBaJ169fx6RJk8TmMkkkNjYWsrKyCAwMxLVr1/D48WM4OTlh1apVuHfvHng8Hk6dOtXcYnJ8oVy/fh3GxsZMLsnnz58zjmw1NTX06tULTk5OEqUXRdsiIiLQqVMnTJs2TawIDQBs27YN33zzDav1YlP2XnJyMjQ0NODg4IC7d++Kffbhwwfk5+fj7NmzrLbxOTg4ODjEkTjHU3p6OnR0dFBWVoZ79+5h0aJFMDAwgKKiIszNzZucXNlqRAD1E66joyN4PB7GjBnDtAsjFoB655OysjJiYmK+iF3huro67NmzBzo6OtDR0YGZmRlGjhzJeqOPg4MtfMoxW1VVBTc3NwwdOlSs/d69e7hy5Qru3LnD6ipNgPjiasmSJRgyZAhSUlIgEAhQWlqKqKgotG7dWqyKESA+HjYuskRlWrNmDUaMGAFjY2N4e3vj0qVLAOoT4rZs2RI7duzAr7/+iuHDh8PT05O1lVj/DAcOHICmpibatWsHHR0dmJiYoLKyEgUFBejUqRNTrY+D468iqhcb2krz5s1Du3btUFJSwvStqKjA1atX8fTpU4nSi5cvX8bNmzeZynwCgQDr16+HlZUVfHx8mDH+1newBdF7lpSUhB9++IH5+8cff4S2tjb8/f2Rn5/f5DUAZzNycHBwSAoS53jKy8uDhYUFunTpAg0NDXh7eyM2NhZPnz6FgoKCWElctiJ6Fv3jx48IDQ3FokWLYGpqimnTpjH9RHfC3dzcMGjQoM8u67/J69ev8fDhQzx9+vSLWFhxcHxuEhIS4O/vj4qKCuYdevToEZSVlbF9+/ZPXsfGBUhDli5dCnV1dRw9elRsF1/ofGrTpg2Tt0WSWLRoEdq0aYPdu3cjMTERFhYW0NXVRXFxMd68eYP58+dDQUEB+vr66N279xd1jKSwsBCXLl3ChQsXmGdw4cKF6Nq1K4qKippZOo4vhYiICCxevBgXL15k2goLC2FpaYlNmzZBIBCI5ccUIgl6MSAgAJqamtDS0oKamhoCAgJQWVkJgUCAsLAwWFtbw8/Pr1HkExv1h+jvfefOHZiYmMDc3FysynFcXBx0dHQwZ84cMecTBwcHB4fkIXGOJ4FAgKysLISFheHIkSN49+4dAKC4uBiWlpb4+eefm1nC3+ZThk15eTkiIyNhbGws5nzi8/m4ffv2b177pfClj4+D45+koqIC/v7+6NmzJ3R1dbFy5UpkZ2cDqM8XN2XKFJSWlkrke/XgwQP06NEDP/30k1i7cPH07t07bN68GTweD5s3b24OEf8SDx8+hJmZGc6fPw+g/midkpKSmJOwqqoK165dw7Fjx77oYyR37tyBh4cH2rRpw/qiGBySRXBwMOzt7aGiooKgoCCcO3cOAODn5wc7O7tmlu7PIeowyszMRIcOHXDhwgVcunQJe/bsQYsWLZjCCnw+H2FhYTA0NGSKFUgCCxYsgKurK6ytraGmpoYuXbpg586dzOdxcXFo3749Jk+ejOfPnzejpBwcHBwcfwceIFKHmyUAECuBKxAISEpKqlE7EVFNTQ29ffuWZsyYQa9fv6aLFy+yrjxsU6xfv56uXLlCAoGA5s+fT9bW1vThwweKj4+n2NhY6t69O4WHh9OkSZNISUmJDh48SET/+y04ODg4+Hw+SUtL07Jly+jatWt08eJFWrp0Kb169Yri4+Pp0KFDZGVl1dxi/i4N9VpeXh7Z2tpSWloamZmZifWtrq6m2tpakpKSovT0dHJxcSEZGZnPLfJf4tatW+To6EgPHz6kn3/+mdzd3WndunXk6+tL5eXllJycTCNGjKCvvvqKuUZ4j78k6urq6Pbt27R7926aOnUqde/evblF4vjCKCkpoTNnztCaNWuorq6OTExMaOLEiTR8+HDatm0beXl5NbeIf4rY2Fi6ePEiqaqq0vr165n2rKwsGjBgAIWGhlJgYCAJBAJKTk6mr7/+WiL0RlxcHM2bN49+/vln0tfXp+rqapo8eTJ9/PiRpk+fTlOnTiUioq1bt9KJEycoJSWFs4E5ODg4JBRWam+hcykhIYGePXvGTDINnU7V1dWUnJxMkyZNotevX1NGRgZJS0sTn8//7DL/HgKBgPl3SEgIhYWFkYqKCpWUlFD//v0pOTmZlJWVafLkyeTn50dXrlwhExMTev/+PSUnJzPXchMuB8d/C1HdQVTvmBf+J1xYrFixgnbu3EkbN26k+Ph4unXrFr1+/ZoSEhKaQ+Q/jVCvzZgxg+Li4khBQYHevXtHT58+JaJ654twj+Tq1auUkpJC8vLy5OrqSjIyMlRXV9dssn+KhveNiEhJSYmMjIxoy5Yt5OHhwTidiIju379Pp06dYsYsRBIWj38WGRkZMjExodDQUM7pxPGXaMrOA8C0q6mp0dixY+no0aO0fv16unv3Ls2bN4/4fD7dvHnzc4v7tygsLKRDhw7Rvn376O3bt0RUP9aamhqytram4OBgSklJodLSUpKSkqKJEyey1hZuyKNHj6hHjx7Uu3dvUlFRobZt21JMTAwJBAJavXo1xcXFERGRn58fHTx4kKSkpJrUrRwcHBwc7Ie1XoxHjx7RmjVr6Ny5c0TUtJEhJydHGhoaNGbMGMrMzCRZWVmqq6tjpaEuXFi9ePGCiIhSUlJox44ddOzYMQoMDCQPDw/as2cPKSsrk6enJ507d44SEhIoKyuLGRcHB8d/DykpKaqurqZDhw5RTU0N8Xg84vP5xOPx6PHjx/Tu3TsiItLS0iJPT086cuQI+fv7k6+vL23cuLF5hf8dRANuz58/TykpKaSlpUX6+vo0depUmj9/Pl24cIGkpaWJx+NRbW0thYSEUHZ2tpieZ1vEk2gE15YtWygxMZGIiPT19UlZWZmCg4Np7ty5jNOpsrKSli5dSmVlZWRubt5scn9uZGVlm1sEDglFWlqaKioq6OTJk1RdXS3WfuPGDebvtm3b0pAhQ+jKlSu0bNkyWrZsGUVERDSHyH+Zdu3aUWBgINnb29PevXvpxIkTxOPxSE5OjoiIlJWVCQApKiqKXcdGW1iIUPfLy8tTVVUV1dTUkJSUFNXW1pKOjg6FhobSy5cv6ccff2Q2X6WlpQkAtwHLwcHBIaGw8qidEFdXV3r79i3jfPo92H4k4ciRIzRq1CjS09Oj5ORksrCwICKi2tpa+u677ygiIoISEhLIzc1N7Dq2j4uDg+PfZfPmzZSamkoTJ06kiRMnkoKCAu3du5d8fX0pIyODevToQUSNjykT1esXti/wExMT6fr166ShoUFLliwhovrIpg0bNlB6ejr5+/uTQCCgrKwsevPmDeXk5LDO2dQUQUFBtGfPHpo5cyZNmzaN2rZtSwKBgAYOHEiFhYU0YcIEUlBQoHPnztHr16/pxo0bJCsryx2p5uD4AyQmJtI333xDO3fupJEjR1KLFi0oNTWVXF1d6fz589S/f38iatqGqqurY6UOEX33G+qBS5cuUUREBOXm5tLGjRtpyJAhVF5eTq6urqSkpESpqamN9D/buX37NpmYmNB3331Hy5YtY9pPnDhBO3bsYKK4jh07xjjaODg4ODgkE1bMug0nV6GRsGrVKnJycqKkpCSaMGHC734P250zffr0IV9fX9q+fTsVFRURUf3YZWVlaeXKlSQtLU0TJ04kDQ0NGjx4MHMd28fFwcHx7zJ16lR69eoVpaenU+vWram2tpb8/PwoJCSEcToRNT6OTMT+qJInT55QXFwcZWdn0+zZs5n2Pn360KpVq6hXr160Z88eatu2LXXs2JFOnDjBHK9j48JRSFRUFMXGxtLp06epV69eRPQ/J+CZM2coKCiIrl69SjIyMtSrVy9at26dRIyLg4MteHh40Js3b2jJkiWkrq5OxcXF5OPjQ9u2bWOcTkRN21BsfMdEbeEdO3ZQZmYmycnJkYmJCc2cOZP69u1Lc+bMofDwcHJycqJOnTqRtbU1lZeXU1paGvF4vCY3H9hMz549aefOneTj40Pl5eX09ddfU+vWrWnTpk1kbW1No0ePpu7du9OFCxdoyJAhzS0uBwcHB8ffoNkjnkQnyUOHDtGQIUNITk6O5OTkqLi4mLy9vUlLS4u2bt0qURPqp3as379/TzNnzqRDhw7RqVOnyNramhlXbW0t7dq1i7y9vVlpFHFwcHx+hLqkvLyctmzZQqmpqXTjxg0KDw+nmTNnfhHRMcePH6eIiAi6ceMGnTx5kkxMTMQ+r6yspBYtWjB/s905U1dXR7NmzaKvvvqKVqxYQQ8fPqQrV67Qxo0bqV27duTv70+2trZUU1NDMjIyzP1j+7g4ONiCqN7btWsXffvtt/Tu3Ttav349ffPNN80s3d8jODiYEhMTaezYscTn8+no0aP09ddfU1hYGBERZWdnU2RkJF25coUWLlxI06dPJ6L6YjuSGhV08OBBmjlzJsnJyREA0tTUpKysLHr16hUNHTqUDhw4QMbGxs0tJgcHBwfH36BZLVxRw+HRo0c0ffp0ateuHZmbm1NAQAB17dqV5s+fT/b29uTu7k79+vVrTnH/MKLjiouLo/v371N5eTnZ2dnR6NGjadeuXcTj8WjYsGF08uRJxvkkKyvL5PzgFiAcHBxE9Tme6urqqFWrVqSrq0s5OTnUo0cPatWqFbPQkBTn06fkdHBwIBkZGQoPDycfHx/auXMn9erVi/h8PklJSZG8vDzTFwDrdaOMjAxVVFTQrl27yMDAgLZv305KSkpkY2NDmZmZFBISQjY2NmKLREkYFwcHWxDqRRkZGTIwMKDS0lJSUVEhLS0tqq6uFtMZkkR8fDylpKRQamoqWVpa0t69eykmJoaioqLo/fv3FB0dTVZWVlRdXU3S0tK0adMm6ty5Mw0cOFBinU5E9ak1rKys6Pnz51RbW0s2NjYkJSVF27ZtI2lpadLU1GxuETk4ODg4/ibNZuVmZmaSsbExKSsr09KlS6lVq1b07Nkz2rp1K50/f57Mzc1p6tSpZG5uTu7u7vTTTz+RtbU1EbG/sptQvqCgIEpISCB3d3d69eoVLViwgDIzMyk8PJw2bNhAUlJS5OjoSIcPHyZbW1ux7+AWIBwcHEJkZGRo37595OfnR+vXr6fi4mI6duwY8fl8cnd3l4hFlqjTKT4+ni5fvkytWrUiMzMzcnNzoyFDhlBtbS1t2bKFfHx8aMeOHWRsbNwomaykRL2uXbuWpk+fTiEhITRt2jRycHAgU1NTOnz4MK1fv57Ky8tJVVWV6S8p4+LgYAsyMjK0f/9+8vLyori4OPr1118pODiY+Hw+jRw5khQUFJpbxN+loTP+48eP5OnpSZaWlvTTTz+Rr68vrV69moiIAgICSEVFhcLCwhhH0+bNm2nSpEm0e/duGjBgQHMN4x9BR0eHdHR0iIjo7t27tHbtWkpLS6PTp09T27Ztm1k6Dg4ODo6/DZqB4uJiKCkpYeTIkZgxYwaUlZVx8+ZNsT6JiYnw8/ODpqYmeDweOnTogPfv3wMABAJBc4j9p0hPT4e+vj4uX74MANi3bx8UFBSQkJDA9Hn37h0cHR0xePDg5hKTg4ODBQgEAvD5/E9+fvv2baiqqmLTpk0AgMrKSixduhR2dnb46aefPpeY/whBQUHQ1taGp6cnPD090a5dO6xfv575PD09Hc7OztDT08OjR4+aUdLfZvHixbhx48bv9ispKWH+zefzYW9vDzc3N4mYxzg4mpPf04u5ubnQ09NDVFQU0xYeHg5FRUX8/PPPn0PEf4zQ0FAcOHAAdXV1ePz4MYqKimBsbIywsDAAwM2bN9GmTRvweDysXLmSue7ChQvw8vLC48ePm0v0f5za2lrk5OQgICAAd+7caW5xODg4ODj+IT6r4+n06dOoqakBABQWFkJBQQGKioq4cOECgHqjXNQYr66uxuPHjxEYGAh9fX0EBwd/TnH/Frt27cKAAQMAAPv374eSkhK2bt0KAPj48SMyMjIAAO/fv/9Nw4qDg+O/RUpKCpKSknDkyBGm7cGDB8jOzgYARl+Ul5dj+/btEqU/du3ahY4dOzJjSUxMhKysLOTl5bF06VKmX2pqKgIDA1FXV9dcov4m79+/h4yMDPr37//JhZHofSkrK0NycjIcHBzQs2dPZh7knE8cHE1TVlYm9vf+/fuxYcMGpKWl4e3btwCAFy9eIDMzE4D4+5aUlMRa3SFEVN64uDhoa2szehEAzp8/j06dOuHZs2cAgLt378Ld3R3p6emNxlZZWfl5hP7MCPUkBwcHB8eXwWc7zxUaGkqHDx+mS5cukUAgoHfv3jHn8H/44Qfq1q0btWnThoj+F3osIyNDHTt2pJCQEJKXl6crV65ITO4jGRkZ0tXVpfT0dJo6dSqtW7eOyd90+vRpysrKoq5du5K6ujoRfTr3CQcHx5fL5MmTSUFBgaKjo4mIaN68eZSQkECtW7emqqoqOnz4MO3cuZM6d+5MAoGAiOqP8vL5fGrZsiWTVFYS9EddXR09ffqUfH19mWMks2bNotWrV9P79+9p5cqVpKKiQvPnz6dRo0bRqFGjiKjpUujNiUAgIGVlZXr58iWZm5uTr68vbdu2jbp37y7WT/R+FBYW0rVr10hFRYV++uknrnodB8dvsGjRInry5AlFR0eTqqoqBQQE0I8//kjKysokLS1N5ubmtGrVKurQoQNpaWkR0f/0orS0NLm5uRER+3SHKEL9cOnSJcrNzaVly5aRpaUlo8tbt25NxcXFFB8fT5MmTaIFCxaQkpIS2dvbE4/HY/Lf8Xg8iThS+Fdge0VWDg4ODo4/yef0ctXW1gIAs0NcV1eHhw8fQkNDA87OzswuVlPk5uZCQ0MDeXl5n0XWv0teXh7k5OTA4/EQGxvLtFdUVMDe3h5eXl7cbjcHx3+Y8vJyrF27Furq6ggODsbHjx/Rv39/3L59G0+ePEFSUhJUVFQwYcIE5hq27+KL0pR+Ky0tRX5+Pp49ewYjIyOEh4cDADIyMtCyZUvweDwmMpTNCOey169fo127dujXr99vHgnh8/koLi5mfhNJuo8cHJ8TgUCA7777DtbW1vD19UV2djacnZ1x/fp1VFVVYceOHbC1tYWzszMTDSRJUZ9C+Hw+cnNzoaCgABkZGaxdu5b5TCAQ4MOHDwgJCYGqqir09PRgZmbGRUpycHBwcEg0n2WLvLq6mojqo4DS09OpZ8+elJSURNXV1dSpUyc6ceIEZWdnk7e3N71+/ZoEAgF5enpSVFQU8x3Hjx8nOTk5UlNT+xwi/226du1Ku3fvJgUFBcrLy6Nz587R2bNnycXFhYqKimjbtm3E4/EIQHOLysHB0Qy0bNmSfHx8aMWKFbRz506aNGkS6enpUadOnUhfX5/GjBlDsbGxlJaWRpMmTSIiImlpaSbyic0IBAImWfaHDx+oqqqKKioqSFVVlQwNDenOnTskLS3NjKtly5Y0ZswYSklJYaK42IwwYklDQ4NycnKooKCAfH196e7du032l5KSojZt2jA6n61RGBwczQkA4vF4tHz5cho9ejTl5eVRaGgoSUtLU48ePUheXp68vb1p2rRp9P79e5o9ezY9f/6cpKSkJMKWEpVRSkqKevXqRXFxcdS6dWs6e/Ys3bt3j4jqCw0oKSnR3Llz6erVqxQbG0uXL18mWVlZqqur4woRcHBwcHBIJDz8y7O16BGQhw8fUufOnWnq1KmUmppK0dHR5OLiQgoKCpSbm0v29vbUpk0bUlBQoIqKCrp9+zYTartw4UJyc3Oj3r17/5vi/qPw+Xzat28fBQYGEhFR27ZtSVtbmw4ePEiysrKsDgPn4OD49xDVix8+fKDExERau3YtqaurU05ODtOvpqaG0tLSyMvLiywtLSktLa25RP7DiI5t7dq1lJmZSc+ePSMLCwvy8vIiKysrysjIIAcHB4qMjKSRI0fStGnTSF1dneLi4ojH47HyGNpvHWd8/fo1mZqakr6+fpPH7jg4OP4YwvdMIBDQunXrKD4+niorKykvL0/sSNmPP/5IsbGxVF1dTSkpKaSpqdmMUv8+QqcaEVFycjK9evWK5syZQ0REu3fvpqCgIBo7dizNnj2bDA0NG11DxO6jgxwcHBwcHL/Hv+p4OnHiBCUlJVFcXBz5+/vT7du36eTJkyQrK0ve3t6UnJxMu3btYpxPr169ovDwcFJRUaHg4GCSkZGhmpoakpOT+7dE/Cy8efOG3r17R/Ly8qSrq8vahRUHB8e/j6gD48GDB6Srq0tERHFxcTR//nz65ptvKDw8nOlfU1NDBw8epLi4OEpPT2d9Lichixcvpu3bt9PGjRtJIBDQpk2bqKioiG7cuEEAKDQ0lLZs2UJaWlqkoqJCV65cIVlZ2UaLLTYges+2b99O9+/fp8LCQgoMDCRDQ0Nq3bo143zq2LEjbdu2jbp169bMUnNwSA5NOXYFAgFFRkbS1q1bqX///hQWFsbkAiUiio6Optu3b9PGjRtZrRdFx3b37l3y8PAgaWlp8vf3Jw8PDyIiio+PpyVLltDYsWNp1qxZjPOJg4ODg4PjS+FfczzV1tbSli1baMeOHSQvL09Pnjyhy5cvU+fOnZk+06dPpz179lBMTAyNGDGCWrVqJbbo+FKdM5KQCJiDg+OfR/Td//bbb+ny5cs0c+ZMGjVqFL1//552795N3333HXl7e1NYWBhznagulAT9kZ+fTxMmTKCIiAgaMGAApaen09dff03h4eHMUbrq6mq6c+cOvXr1iuzt7UlaWpr1On/hwoUUFxdHzs7OjBNt4cKF5OrqSlpaWvT69WuysLAgBQUFSk9PJ319/eYWmYOD9YjqtCtXrpCCggIBoF69ehEAioiIoAMHDpCxsTGtWbOGWrdu/ZvfwVYCAwPpl19+oaKiIrp//z5paGhQYGAgeXl5EVG982np0qU0aNAgWrlyJbVr166ZJebg4ODg4PgH+TcTSAkEAjg6OoLH42HMmDFMe1VVFfNvb29vKCsrIyYmBtXV1f+mOBwcHBysYOnSpVBXV8fRo0dRXFzMtJeWliIqKgpt2rRBcHBwM0r497h58ya0tbVRVlaGw4cPQ1FRkUkaXlZWhp07d+LXX38Vu4btCbd37dqFDh064MaNGwCA7Oxs8Hg86OrqIjw8nBlPUVERRo0axfrxcHCwjYCAAGhqakJLSwtqamoICAhAZWUlBAIBwsLCYG1tDT8/PzGdCUhGsu3Y2Fioqqri+vXrKCkpQVFREYYNG4a+ffsiJiaG6bdlyxa4uLhIZMJ0Dg4ODg6O3+If31rG/0cs8fl8qqyspAEDBlDv3r3pxIkT5OXlRbt27SJ5eXmqqKigli1b0o4dO6isrIwSExNp6tSp/7Q4HBwcHKzi4cOHlJKSQrGxseTk5MS0AyBVVVWaNGkS8Xg8mjVrFrVv355mzpzZjNL+Pk1FGigpKZGRkRFt2bKFVq5cSevWrSNfX18iIrp//z6dOnWKevbsSV999RVzDZtzl9TU1FBtbS0FBgZS7969KTU1lab+X3t3Hh/juf9//DUziSTIgiaxN3oQihJ1aGhLD8dSnCC21pIQ+yGURog2VK2pUlXkWCKUSluCUrUT+76HFD12GtUGRWSy3L8//DJfqeh2Sgbv5+Ph8TD3+rnvZO7M9Znr+lxduhAbG8u+ffuIjIzEbDYTGBhIqVKlWLJkCaCaLCK/xrinh/u2bdtYtGgRixYtwtHRkdOnTxMSEsL333/P/PnzGTRoEHB3qGuZMmVstTMBuxuam5tTp05RuXJlW51Ss9lMTEwMgYGBjBkzBpPJRHBwML1796ZHjx62Olf23otLRETk9/pLh9o96I/k7du3mTVrFrNnz6ZGjRrMnj3btv2xY8eoXLmy/sCKyBPpl8+248ePU69ePVauXMmLL76YY9u0tDTS09Mxm8188803BAQE2PXQs3uvbdq0abi6utpqlrRq1YqlS5fy7rvv8t577wGQmppK69atMZlMfPXVV3b7zDdyqTOVlJSEu7s7aWlpBAQEEBwczFtvvcW5c+eoXLkyZrOZ6Oho2rdvb5d1qkTs1Zw5c9i2bRseHh5MmDDBtnz79u28+uqrjB07lrCwMLKysoiLi6Ndu3aPTUI3+1nw/vvv89VXX7FlyxacnZ1JT0/H0dGRjRs30qxZM/z9/enWrRvt27fPsZ+IiMiT4i/91J/diJgwYQJt27aldevWbN++nfz58xMcHEy3bt04cOAAnTp14sqVKzRu3Jjhw4fb9n0cpgkXEfkjsp+LPXv2JDY2FmdnZ65du8bZs2eBu71isvP/e/bsIT4+HicnJwIDA3FwcCAjIyPPYv8t2dc2ePBgxowZw/nz5/n+++8BWLRoEXXq1GHevHlEREQwcuRImjZtytmzZ1myZIndPvOtVmuOOoOZmZkAVKhQgWLFinH27FkyMzOpX78+AFevXqVz585ERkbSpk0b4PHogSFiDy5cuMDSpUv54osv+PHHH4G7SRer1Urt2rUJDw8nPj6elJQUzGYzb775JhaLxfa+tHfZz4IWLVpw4MABxo8fD2CbsdlqtdKkSRMMw2D27NlYrdYc+4mIiDwp/pLE072Nh5EjRxIVFYW7uzs//fQTr7zyCnFxcbi5uREUFETv3r3ZvXs3fn5+XL9+nbi4uP8Lxk6//RYR+aPu7UyakJBAfHw8xYoVo0yZMnTp0oWBAweyefNmLBYLJpOJ9PR0Ro4cyc6dO3N8m2/PPZ4APvnkE+bMmcPXX39NREQERYsWtfXa2rBhAy1atGDPnj3s2LGDqlWrcvDgQRwdHcnIyLCrZ/7GjRsBbLOoRkVF0bRpU/71r38xfPhw0tLSAPj5559JTk4mKSmJI0eOMGLECG7dusXAgQMfqwaxiD0oWbIkYWFhNGrUiM8//5zVq1djMpls70M3NzcMw6BgwYI59ntcejxlq1KlCrNmzWL06NEMHjyYffv28d///pcpU6ZQvXp1PvnkE9avX8/mzZvzOlQREZGH4i9p0WQ3Hi5evAhAfHw8L7/8Mqmpqbz33nt06tSJrKws3nzzTTp37kyzZs04duwY9erVeyxmMhIR+aOyv7H+9NNP2bdvHwMGDKBRo0YAhISEcOPGDQICAggNDSUrK4vt27fzww8/sHLlyrwM+w/JyMjg6NGj9OnTh6pVq3LixAl2797Nxx9/TMmSJQkNDWXSpElYrVYcHBxsfyvs7Zk/c+ZMBg8ezEcffURQUBDjxo1j7NixdOvWjbS0NCZPnszWrVuZM2cOzZo1o169evTq1YuCBQvi7e3N4sWLbcd63BrEIo/KvUNz7/3/yy+/bHvf9O3bl48//pgGDRpw69Yt1qxZQ9GiRe3qefFnBQcH4+rqSp8+fVi4cCGGYeDl5cXAgQNJTk6mbNmyeHl55XWYIiIiD8VfVuPpq6++okWLFvj4+BAXF0fNmjUBSE9P591332XixInMmzfPNn49m4qvisiT6r///S/du3dn586d9OvXj3HjxtnWnT59mi+++ILPPvuMokWLUrp0aaZPn24bXve4NLQ6d+7Mhg0bGDNmDDNmzMDV1ZUKFSqwdetWXF1dWb16tW1YCdhn7ZIjR44wY8YM1q1bR9++fTl79iwNGjSgYcOGAJw9e5a6devi6+vL6tWrgbu92CwWC/7+/voCReQ33JtomjlzJlu3biVfvnz4+fnZJlDYunUrH374IcuWLaNcuXLUrl2b48ePk5CQgJOTk10+O/6Mixcvcv78edLT06lTpw5ms5mhQ4eydOlSNm7cSNGiRfM6RBERkb/cX5Z4unz5Mu+//z4zZsxg8eLFBAQE2D5oZGRkMHz4cMaOHcvatWtttTFERJ50q1atYuLEiRw4cIA1a9bg5+eXY31qaiouLi62149bAuPy5ct0796dpKQkunbtSuPGjalevTrLli1jwoQJLF++HA8Pj7wO8zclJSUxdepUNm7cyJUrV1i2bBn+/v62IsCJiYn4+/vzySef0Llz5xz76gsUkd8nPDycTz/9lNatW5OZmcmKFSto164dUVFRAOzcuZPJkyeze/duhgwZQvfu3YG7tZCyh989SRITExk/fjwrV65k3bp1tlnvREREnjR/qnWT2wx0xYoVY+zYsVy/fp0333yTtWvXUrt2bQzDwMHBgREjRlCqVCnq1q37lwQuImJPHjQzZ+PGjXFwcODDDz+kR48ezJo1i6pVq5KZmYnZbMbJycm2bfbz0p4MGzaMNm3aPLBBVKxYMVasWEFKSgqFChUC7t6L6dOnU7JkSdzd3R9htH9ehQoV6NmzJwDTp09n27Zt+Pv74+joSFZWFiVKlMDHx4cbN27ct6+STiK/be7cucTHx7NkyRJq1arF559/TkxMDJ988gnXr1/nP//5Dy+99BJpaWlYLBamTJlC+fLlqVu37hOZdMrIyMBqteLl5UVCQgKVKlXK65BEREQemj/cwrm3cRUbG0tSUhK3bt3iH//4By1btmT27NmYTCYaNmzImjVrbMknR0dHevXqBTx+3+iLiPyae5+Lc+fOZdeuXRQoUIAXX3yR9u3b06BBA9LT05k2bRo9evRg5syZvPDCCxiGkSNZZW/DSG7cuEFUVBRbtmxh+vTpuTaMsq+9UKFC3Lp1ixUrVhAbG8ulS5dYvnw5JpPJLofI5JYorFy5Mv369cNqtTJp0iTc3Nzo0aMHZrOZAgUKYLVaSU9Pz6OIRR4vv3yP/fzzz3Tu3JlatWqxfPlyevXqxZgxYwAYNGgQ7u7uREVF2RJNU6dOpWPHjixYsIBXX301ry7joXFwcMDPz4/KlSvnGI4sIiLyJPrD2Z97p8+eN28eHTp0IDk5mbfffts2Pn/SpEmYzWaaNGnCsmXLqFevXs6TKukkIk+Q7OdieHg48+fPtxXGDQsL4+LFiwwaNIgmTZpgMpmYPn06AQEBrFu3jr/97W95HPmDZWVl4ebmxqVLl6hRowa9evUiOjr6vuTTvQ3LCxcusHfvXtzd3Vm+fLnd1qu6t0G8ePFikpOTuX79OkFBQZQvX56hQ4disVgYNGgQ+/fvx9PTk6NHj5KVlUW/fv3yOHqRx0P2e2zcuHGUK1eO3r17c/bsWb7//nveeecdIiIieOuttzh8+DCFCxdmwoQJuLu7M2zYMPz9/cnIyMDZ2ZmSJUvm8ZU8XEo6iYjIU8H4E7755hujTJkyxq5duwzDMIwvvvjCcHZ2NubNm2fb5tq1a0aTJk2M+vXr/5lTiIg8VmbPnm0899xzxs6dOw3DMIxPP/3UcHR0NJycnIzIyEjbdkuWLDHCwsKMjIyMvAr1d0tPTzcMwzCuXLlilCxZ0nj55ZeNo0ePPnD7zMxM4+rVq0ZWVpZhGIbdX+PAgQMNb29vo1atWkaZMmUMLy8vY/78+UZWVpZx+vRpo2fPnkaRIkUMPz8/48svv7TdD3u/LpG8lJmZaft/bGysUbx4cdtz0TAMIyEhwShXrpxx7tw5wzAMIzEx0ejQoYPxzTff3PfeSk1NfTRBi4iIyEP1p76GvnTpEqVKlaJmzZosWrSIkJAQJk2aRKdOnbh58yYHDx7k5ZdfJi4ujoIFC/7VuTIREbuSkZHB2bNn6dWrl20YSd++fRkzZgzXr19n1KhRuLu7M3DgQFq0aEGLFi0A+y9Knd1jydPTk/3791O9evUH9nyCuz0cihQpAtytV2XP17Zo0SLmz5/P2rVrKVu2LPnz5yckJITw8HDc3Nxo3rw5oaGhpKamYjKZCAwMxGQy2f3PTCSvZfd02rFjBwcPHmT48OHUqlUrx7Dcq1evMnfuXDp27Mjbb7+Nq6srjRo1sr3HzGYzJpMJZ2fnPL4aERER+Sv8qVnt5s2bx5o1a+jQoQNt27blgw8+sNVvWrp0Kdu3b2fw4ME888wzwIOL7oqIPI6MXGoWXbt2jatXr+Lk5ESjRo3o1q0bAwcOZOvWrTRq1IjU1FSmTZtme1baq197Xl+5coXq1atTpkyZByaf7FFMTAy1a9emQoUKtmVTp05lwYIFbNiwAQcHB9twwPbt27N//36SkpIwm82cOXOG0qVLYzab9bdM5HfIysriyJEjvPTSS2RkZDB69GgGDx4M3H123rx5k48++oiJEyfi4eFBkSJF2LFjB46OjnZZD05ERET+d3/qE3TNmjX58ssvadq0KVOmTLE1pFJTU4mOjuann36yfesN6IO6iDwxsrKybA2jGzducOfOHW7fvo2Hhwdly5bl6NGjWCwWOnbsCED+/Plp1aoV8fHxtqnB7dW9iZUZM2YwcOBA2rZty549e0hJScHLy4v9+/dz+vRpevfuzbFjx/I44t+WkJBAjx49iI6O5tSpU7blKSkpnD9/HmdnZxwcHEhNTQUgMjKSlJQU9u7dC4CPj4+STiK/4d7vMM1mM1WrViU2NpZChQqxceNG27PCZDLh6urKgAED2LNnD3PmzGHXrl04OjqSkZGhpJOIiMgT6k99iq5QoQILFizA2dmZ48ePs2nTJjZu3EhAQACXL18mOjraNpORiMiT4t7kw/jx4+nQoQO1atWif//+7Ny5E4CCBQvy3//+l6+++ork5GTeffddzGYzAQEBWCwWMjIy8vISflX2tQ0ZMoTIyEhu3rxJamoqLVu2ZMGCBVy+fNmWfDp37hytWrXi9OnTeRz1r6tbty6xsbHEx8czZcoUTpw4AUCXLl0wm8107doVABcXFwBbEvGXw8SVdBLJ3b29lOLi4pg8eTIA7dq1Y9KkSRw+fJj//Oc/ORK/BQsWpGzZstSrVw+LxUJmZqbdTUIgIiIif50/NdQO7tYm+eKLLwgLCwOgaNGiFC9enMWLF+Po6Kg6GCLyxIqIiGDGjBl8/PHHZGVlMWXKFC5fvsyBAwcwDIOxY8cybdo0ihUrhru7O7t3735shpHExMQwcuRIli5dSrVq1di1axf+/v6ULFmSAQMG0KFDB7y9vfn+++/p3bs3ixYtsttn/b1/h+bNm0dERASBgYH07duXcuXKERMTwwcffECVKlUYPXo0169fZ+TIkVy7do1NmzYp2STyG+5NxicmJtKpUycsFguhoaF06tQJgLlz5zJs2DBat25N3759KVu2bF6GLCIiInngT3+9ZLFYeOONN2jQoAHXrl3DycmJUqVKYTKZ7HL6bBGRv8LJkydZs2YN8fHxvPrqq3zzzTccP36cDz/80DbEeMyYMbz55pskJyfTqFEjW08ne38uWq1W0tPTCQsLo1q1aixZsoQuXboQGxvLvn37iIyMxGw2ExgYSKlSpViyZAlgn0XSf1ncvHPnzhiGwbBhwzAMg/DwcDp27IirqyvDhw+nRo0aeHt74+3tzYYNGzS8TuR3yH5/hIWFcfr0aVxcXEhKSmL06NFYrVZCQkIICgoC7g5jvXbtGqNGjaJkyZJ5GbaIiIg8Yn+6x9OD6IO6iDzJDh8+TJMmTThx4gTr16+nQ4cOtgkWbt26RVxcHM2aNcPb29u2jz0mZiD3IulJSUm4u7uTlpZGQEAAwcHBvPXWW5w7d47KlStjNpuJjo6mffv2dtuD65dDf5KTk+nfvz9wt/dFds+nsLAwSpUqBdydgcvDwwNfX1/MZvNjkSgUsQexsbG89dZbrF+/njJlypCWlkZQUBA///wz3bt3p0uXLgBMnz6d1atXEx8fr8+JIiIiT5m//FO1PkyIyJMit0S6q6srFStWZNq0aYwaNSrHrJ5JSUmsXbuWKlWq5Eg82WPSyWq1ki9fPgBbUV+LxWKb+S0hIYHMzEzq168PwNWrV+ncuTPPPfccbdq0AbDLpNMvh/5ERUVhsVgoXLgwnTp1svW+iIiIwGQy0adPH3x9ffH3989xDCWdRH6fU6dOUblyZapVqwbc/RwYExNDYGAgY8aMwWQyERwcTO/evenRo4d6E4qIiDyF9MlaRCQX9zaMpk2bhqurK506daJMmTK4ubkRHh7Ou+++m2NWz8jISEwmEzVq1MjL0H/Vxo0bee2112xJp6ioKNavX4+DgwM1atQgIiICJycnfv75Z5KTk0lKSsJkMjFixAiKFCnCwIEDAfvtxfVHh/5cv379vqE/ahCL/LbsnoVOTk7cuXMHq9WKs7Mz6enplChRgrFjx9KsWTPmz5+Ps7Mz7du3x2KxYBiG3mMiIiJPmb98qJ2IyJNk8ODBfPbZZ/Tp04euXbtStGhRsrKyqFu3LhcuXOCNN97A2dmZTZs2ceXKFQ4cOICjo6NdfqM/c+ZMBg8ezEcffURQUBDjxo1j7NixdOvWjbS0NObPn8+LL77InDlzKF26NG3atGH9+vUULFgQb29vtm/fjqOjY15fxm/S0B+RR+fIkSP4+fnx7rvvMnz4cNvy1atXM3PmTFJSUjCbzXz99de2hLeIiIg8XZR4EhF5gE8++YT33nuPdevWUbVqVQDS09NxdHQkPT2dwYMHc/ToURwcHKhQoQIffPABDg4Odlsf6MiRI8yYMYN169bRt29fzp49S4MGDWjYsCEAZ8+epW7duvj6+rJ69Wrg7pA7i8WCv7//Y1Mk/Z133iEhIYGEhATgbg+mixcvEhgYyI8//siwYcMIDg4G/q/nlj0mCkUeF7GxsfTo0YMBAwbQrl07ChUqRGhoKLVr16Zly5ZUqlSJNWvW0KBBg7wOVURERPKAfbceRETySEZGBkePHqVPnz5UrVqVEydOsHv3bj7++GNKlixJaGgokyZNwmq14uDgYEta2HNipkqVKvz73/8G7vb2uXLlCi1btgTuJtSeffZZvv76a/z9/Zk3bx6dO3embt26tv0zMzPt9tpAQ39E8kpwcDCurq706dOHhQsXYhgGXl5eDBw4kOTkZMqWLYuXl1dehykiIiJ5RJ+0RURy4eDgwO3bt5k9ezbz5s2ja9euLFiwgDp16nD+/HlGjhxJeno6+fLlsyUtDMOw68QMQIUKFejZsyevvfYaP/30E9u2bQOwDQ8sUaIEPj4+3Lhx47597bGm072yi523aNGCAwcOMH78eADb8ECr1UqTJk0wDIPZs2djtVpz7Ccif15gYCD79+/nyy+/ZOHChezduxdnZ2eio6OxWCxKPImIiDzF7LuFJCKSh8aPH0/37t0ZOXIkXbt2pXHjxlSvXp1ly5YxYcIEbt26hYeHh217e0xg5DaErHLlyvTr1w+r1cqkSZNwc3OzzTZVoEABrFYr6enpeRTx/65KlSrMmjWLHj16cOvWLdvQnylTpuQY+rN582YN/RH5C5UoUYISJUoAd2eVHD9+PCtXrmTdunUULVo0j6MTERGRvKLEk4g8tYYNG0abNm1s04D/UrFixVixYgUpKSkUKlQIuJvImT59OiVLlsTd3f0RRvvH3Zt0Wrx4McnJyVy/fp2goCDKly/P0KFDsVgsDBo0iP379+Pp6cnRo0fJysqiX79+eRz9/0ZDf0TyTkZGBlarFS8vLxISEqhUqVJehyQiIiJ5SMXFReSpdOPGDYoUKYK/vz/Tp0/PtWF0b+Lm1q1brFixgtjYWC5evMi+fftwdHS01RWyZ4MGDWLBggX4+Phw5coVbt26xcSJE3nzzTc5e/Ys48aNY9GiRZQuXZqIiAhatGiBg4ODrfD24+zixYucP3+e9PR06tSpg9lsZujQoSxdupSNGzeqF4bIQ5Q9GYOIiIg83dTjSUSeOllZWbi5uXHp0iVq1KhBr169iI6Ovi/5dO8QtQsXLrB3717c3d1Zvny5Xc9ed69FixYxf/581q5dS9myZcmfPz8hISGEh4fj5uZG8+bNCQ0NJTU1FZPJRGBgICaT6YlIOoGG/ojkJSWdREREBNTjSUSeUtlJox9++IHq1avj4+OTa/IpW1ZWFikpKRQuXNhuEzMxMTHUrl2bChUq2JZNnTqVBQsWsGHDBhwcHGyJsvbt27N//36SkpIwm82cOXOG0qVLYzabc60L9bjLyMjgyJEjLFiwgC5dumjoj4iIiIjII/JktSxERH6n7B5Lnp6e7N+/nzNnztCrVy8SExNz3d5sNlOkSBFMJhOGYdhd0ikhIYEePXoQHR3NqVOnbMtTUlI4f/48zs7OODg4kJqaCkBkZCQpKSns3bsXAB8fnyc26QR3f95+fn6MHTtWSScRERERkUfoyWtdiIg8QFZWVo7X2b1/PD092bdvH6dPn/7V5FM2e6zpVLduXWJjY4mPj2fKlCmcOHECgC5dumA2m+natSsALi4uANy+fRsPDw8KFiyY4zhPYtLpXhr6IyIiIiLyaD3ZLQwRkf/v3p48M2bMYODAgbRt25Y9e/aQkpKCl5cX+/fv5/Tp0/Tu3Ztjx47lccS/X2ZmJgAdO3Zk1KhRLF68mKlTp3Ly5ElKlCjB8OHD2bFjB23btuXkyZPs3buXkSNHUqxYsRzD8kRERERERP5qqvEkIk+VIUOGEBsby7/+9S8uX77MgQMHGDJkCIGBgRQrVowrV65Qs2ZNnJ2d+eabbyhTpkxeh/yrcptVb+7cuQwbNoxWrVoRHh6Op6cny5YtY/jw4Vy8eBFvb2+8vb3ZsGEDjo6OT+zwOhERERERyXv2PR2TiMhfKCYmhri4OFatWkW1atXYtWsX/v7+REVFYbVa6dChA97e3uzcuZPevXtTunTpvA75V92bdIqLiyM5OZn+/fsTFBQEQEREBABhYWG0adOGNm3asGPHDjw8PPD19cVsNj8WM/OJiIiIiMjjS60NEXkqWK1W0tPTCQsLo1q1aixZsoQuXboQGxvLvn37iIyMxGw2ExgYSKlSpViyZAmAXc5eBzmHDiYmJhIVFYXFYqFw4cJ06tQpR/LJZDLRp08ffH198ff3z3EMJZ1ERERERORh0lA7EXki5TYELSkpCXd3d9LS0ggICCA4OJi33nqLc+fOUblyZcxmM9HR0bRv3z7X/e1RWFgYp0+f5vLlyyQlJeHp6UlYWBghISHA3WF3kZGRvPbaa4waNYqSJUvmccQiIiIiIvI00VfdIvLEsVqt5MuXD4CMjAxMJhMWi8VWSDshIYHMzEzq168PwNWrV+ncuTPPPfccbdq0Aexz5rpfio2NZdasWaxfv54yZcqQlpZGUFAQs2fPxmw206VLF4KCgrh9+zarV6+mePHieR2yiIiIiIg8ZVRNVkSeGBs3bgSwJZ2ioqJo2rQp//rXvxg+fDhpaWkA/PzzzyQnJ5OUlMSRI0cYMWIEt27dYuDAgVgsFtsscfbu1KlTVK5cmWrVquHu7k7RokWJiYkhKyuLMWPGEBsbC0Dv3r1ZvHgxZrOZrKysvA1aRERERESeKko8icgTYebMmbRq1Yq5c+cCMG7cOEaPHk3lypUpU6YMkydP5vXXX+fcuXM0a9aMevXq0atXL5o2bcrly5eZMWOG7Vj2WNPpXtkjpJ2cnLhz5w5WqxWz2Ux6ejolSpRg7NixXLp0ifnz5xMXFwfcvSbDMDR7nYiIiIiIPFKq8SQiT4QjR44wY8YM1q1bR9++fTl79iwNGjSgYcOGAJw9e5a6devi6+vL6tWrgbtD7iwWC/7+/lgslsduhrcjR47g5+fHu+++y/Dhw23LV69ezcyZM0lJScFsNvP111/beoGJiIiIiIg8Sko8icgTIykpialTp7Jx40auXLnCsmXL8Pf3Jz09HUdHRxITE/H39+eTTz6hc+fOOfa119nrfktsbCw9evRgwIABtGvXjkKFChEaGkrt2rVp2bIllSpVYs2aNTRo0CCvQxURERERkafQ4/PVvojIb6hQoQI9e/YEYPr06Wzbtg1/f38cHR3JysqiRIkS+Pj4cOPGjfv2fRyTTgDBwcG4urrSp08fFi5ciGEYeHl5MXDgQJKTkylbtixeXl55HaaIiIiIiDyllHgSkcdWVlbWfTWLKleuTL9+/bBarUyaNAk3Nzd69OiB2WymQIECWK1W0tPT8yjihyMwMJCXXnqJ8+fPk56eTp06dTCbzURHR2OxWJR4EhERERGRPKOhdiLyWLo36bR48WKSk5O5fv06QUFBFC9enDNnzhAVFcWnn35Khw4d8PT05OjRoyQmJnLs2LHHqpbTH5WYmMj48eNZuXIl69ato1q1ankdkoiIiIiIPKWe3JaXiDzRspNOgwYNYsGCBfj4+HDlyhU++ugjJk6cyJtvvsngwYPJyspi0aJFlC5dmoiICFq0aIGDg8NjW9Ppt2RkZGC1WvHy8iIhIYFKlSrldUgiIiIiIvIUU+JJRB5bixYtYv78+axdu5ayZcuSP39+QkJCCA8Px83NjebNmxMaGkpqaiomk4nAwEBMJtMTm3QCcHBwwM/Pj8qVK+Po6JjX4YiIiIiIyFNOQ+1E5LEQExND7dq1qVChgm3Z1KlTWbBgARs2bMDBwcE2fK59+/bs37+fpKQkzGYzZ86coXTp0pjN5lzrQomIiIiIiMjDodaXiNi9hIQEevToQXR0NKdOnbItT0lJ4fz58zg7O+Pg4EBqaioAkZGRpKSksHfvXgB8fHyUdBIREREREckDaoGJiN2rW7cusbGxxMfHM2XKFE6cOAFAly5dMJvNdO3aFQAXFxcAbt++jYeHBwULFsxxHCWdREREREREHi21wkTErmVmZgLQsWNHRo0axeLFi5k6dSonT56kRIkSDB8+nB07dtC2bVtOnjzJ3r17GTlyJMWKFcsxLE9EREREREQePRUXFxG7ZRhGjiLgnTt3xjAMhg0bhmEYhIeH07FjR1xdXRk+fDg1atTA29sbb29vNmzYoOF1IiIiIiIieUzFxUXELhmGgclkAiAuLo7k5GT69+8PwNy5c4mIiCAwMJCwsDBKlSoFwI4dO/Dw8MDX1xez2UxGRoat4LiIiIiIiIg8emqRiYjdubeXUmJiIlFRUVgsFgoXLkynTp0ICgoCICIiApPJRJ8+ffD19cXf3z/HMZR0EhERERERyVtqlYmI3clOOoWFhXH69GlcXFxISkpi9OjRWK1WQkJCbMmnyMhIrl+/zqhRoyhZsuR9xxAREREREZG8o8STiNil2NhYZs2axfr16ylTpgxpaWkEBQUxe/ZszGYzXbp0ISgoiNu3b7N69WqKFy+e1yGLiIiIiIjIL6jGk4jYpXfeeYeEhAQSEhKAuz2YLl68SGBgID/++CPDhg0jODgYuDvzncViUSFxERERERERO6MWmojYlexcuJOTE3fu3MFqtWI2m0lPT6dEiRKMHTuWS5cuMX/+fOLi4gCwWCwYhqGkk4iIiIiIiJ1RK01E7Er2THYtWrTgwIEDjB8/HgBHR0cArFYrTZo0wTAMZs+ejdVqzbGfiIiIiIiI2A/VeBIRu1SlShVmzZpFjx49uHXrFu3ataNQoUJMmTKF2rVr07JlSypVqsTmzZtp0KBBXocrIiIiIiIiuVCNJxGxa4sXL6ZPnz7ky5cPwzDw8vJi+/btJCcn889//pNFixbxwgsv5HWYIiIiIiIikgv1eBIRuxYYGMhLL73E+fPnSU9Pp06dOpjNZqKjo7FYLHh5eeV1iCIiIiIiIvIA6vEkIo+VxMRExo8fz8qVK1m3bh3VqlXL65BERERERETkAdTjSUQeGxkZGVitVry8vEhISKBSpUp5HZKIiIiIiIj8CvV4EpHHTnp6um2WOxEREREREbFfSjyJiIiIiIiIiMhDYc7rAERERERERERE5MmkxJOIiIiIiIiIiDwUSjyJiIiIiIiIiMhDocSTiIiIiIiIiIg8FEo8iYiIiIiIiIjIQ6HEk4iIiDx1Nm3ahMlk4tq1aw/1PJ06dWLMmDEP9Rx/pTNnzmAymTh48GBeh5LnTCYTS5cu/cuOFxwcTIsWLf6nY1itVnx8fNi7d+9fE5SIiMgjoMSTiIiI2JXg4GBMJhO9evW6b92///1vTCYTwcHBjz6wP+jQoUOsXLmS0NDQHMsTExNp27Ytnp6eODk5Ub58eSIjI7l9+/YjjS+3REipUqW4fPkylStXfujnv3HjBsOGDaNChQo4OztTtGhRGjRoQHx8PIZhPPTzP2qTJ08mNjbW9rpevXoMGDDgDx0jX758vP3224SHh/+1wYmIiDxESjyJiIiI3SlVqhRxcXGkpqbalt25c4fPPvuM0qVL52Fkv9+UKVNo06YNBQsWtC3buXMntWrVwmq18vXXX3PixAlGjx5NbGws//znP7FarXkYMVgsFooWLYqDg8NDPc+1a9eoXbs28+bNY+jQoezfv5/NmzfTrl07Bg8ezPXr1x/q+fOCu7s7Hh4e//NxOnTowNatW0lMTPzfgxIREXkElHgSERERu1O9enVKlSpFfHy8bVl8fDylS5fGz88vx7ZpaWmEhobi5eWFs7MzL7/8Mnv27MmxzcqVKylfvjwuLi689tprnDlz5r5zbt26lVdeeQUXFxdKlSpFaGgot27dsq2fNm0a5cqVw9nZGW9vb1q3bv3A+DMzM1m0aBHNmze3LTMMg5CQECpWrEh8fDw1a9bk2WefpU2bNixfvpwdO3YwadIkIPchb9euXcNkMrFp0ybbsqNHj9KkSRMKFiyIt7c3nTp14urVq7b1ixYtokqVKri4uFCkSBEaNGjArVu3GDFiBHPnzmXZsmWYTCbbcXM7b0JCAjVr1sTJyYlixYoxZMgQMjIybOvr1atHaGgogwcPpnDhwhQtWpQRI0Y88N4AREREcObMGXbt2kVQUBDPP/885cuXp3v37hw8eNCWrEtJSaFz584UKlSI/Pnz06RJE06ePGk7TmxsLB4eHqxYsQJfX1/y589P69atuX37NnPnzsXHx4dChQoRGhpKZmambT8fHx/ef/993njjDQoUKECJEiWYOnXqr8Z8/vx52rZti4eHB4ULFyYgIMD2e5SUlET+/Pn57LPPbNt/8cUXuLi4cOzYMSBnD7Pg4GASEhKYPHmy7f6fPn2asmXLMmHChBznPXjwICaTiVOnTgFQqFAh6tSpQ1xc3K/GKyIiYi+UeBIRERG71LVrV+bMmWN7HRMTQ5cuXe7bbvDgwSxevJi5c+eyf/9+ypYtS6NGjfjpp5+AuwmDVq1a0bx5cw4ePEi3bt0YMmRIjmN89913NG7cmMDAQA4fPsznn3/O1q1b6du3LwB79+4lNDSUkSNH8u2337Jq1SpeffXVB8Z++PBhrl+/To0aNWzLDh48yLFjxxg4cCBmc86PYFWrVqVBgwYsXLjwd9+fa9eu8Y9//AM/Pz/27t3LqlWrSE5Opm3btgBcvnyZN954g65du3L8+HE2bdpEq1atMAyDt99+m7Zt29K4cWMuX77M5cuXqV279n3nuHjxIq+//jp///vfOXToENOnT2f27NmMGjUqx3Zz586lQIEC7Nq1i6ioKEaOHMnatWtzjTsrK4u4uDg6dOhA8eLF71tfsGBBW4+r4OBg9u7dy1dffcWOHTswDIPXX3+d9PR02/a3b9/m448/Ji4ujlWrVrFp0yZatmzJypUrWblyJZ9++in/+c9/WLRoUY7zfPDBB1StWpUDBw4wZMgQ+vfv/8CY09PTadSoEa6urmzZsoVt27ZRsGBBGjdujNVqpUKFCkyYMIE+ffpw7tw5Lly4QK9evRg/fjzPP//8fcebPHky/v7+dO/e3Xb/S5cufd/vPMCcOXN49dVXKVu2rG1ZzZo12bJlS66xioiI2B1DRERExI4EBQUZAQEBxpUrVwwnJyfjzJkzxpkzZwxnZ2fjhx9+MAICAoygoCDDMAzj5s2bhqOjo7FgwQLb/lar1ShevLgRFRVlGIZhDB061Hj++edznCM8PNwAjJSUFMMwDCMkJMTo0aNHjm22bNlimM1mIzU11Vi8eLHh5uZm3Lhx43ddw5IlSwyLxWJkZWXZlsXFxRmAceDAgVz3CQ0NNVxcXAzDMIzTp0/ft21KSooBGBs3bjQMwzDef/99o2HDhjmOcf78eQMwvv32W2Pfvn0GYJw5cybX82Xf53v98rwRERGGr69vjuuYOnWqUbBgQSMzM9MwDMOoW7eu8fLLL+c4zt///ncjPDw81/MmJycbgDFx4sRc12c7ceKEARjbtm2zLbt69arh4uJifPHFF4ZhGMacOXMMwDh16pRtm549exr58+c3fv75Z9uyRo0aGT179rS9fvbZZ43GjRvnOF+7du2MJk2a2F4DxpIlSwzDMIxPP/30vvuQlpZmuLi4GKtXr7Yta9q0qfHKK68Y9evXNxo2bJhj+1/e77p16xr9+/fPEcPFixcNi8Vi7Nq1yzCMu7/LzzzzjBEbG5tju8mTJxs+Pj653zgRERE783AH8IuIiIj8SZ6enjRt2pTY2FgMw6Bp06Y888wzObb57rvvSE9Pp06dOrZljo6O1KxZk+PHjwNw/PhxatWqlWM/f3//HK8PHTrE4cOHWbBggW2ZYRhkZWVx+vRp/vnPf/Lss8/y3HPP0bhxYxo3bkzLli3Jnz9/rrGnpqbi5OSEyWS6b53xK4Wz8+XL98B1v3To0CE2btyYo4ZUtu+++46GDRtSv359qlSpQqNGjWjYsCGtW7emUKFCv/scx48fx9/fP8d11KlTh5s3b3LhwgVbva0XXnghx37FihXjypUruR7z167/l+d2cHDI8bMrUqQIvr6+tp8tQP78+fnb3/5me+3t7Y2Pj0+O++Lt7X1fPL/8HfD39+ejjz7KNZZDhw5x6tQpXF1dcyy/c+cO3333ne11TEwM5cuXx2w2k5iYmOvP/9cUL16cpk2bEhMTQ82aNVm+fDlpaWm0adMmx3YuLi6PvBi9iIjIn6XEk4iIiNitrl272oa7/VYNnv/FzZs36dmz530z0AGULl2afPnysX//fjZt2sSaNWuIjIxkxIgR7NmzJ9eC0c888wy3b9/GarXakknlypUD7iZUflmnKnt5+fLlAWxD8e5N0tw7vCw75ubNmzN+/Pj7jlWsWDEsFgtr165l+/btrFmzhilTpjBs2DB27dpFmTJlfued+X0cHR1zvDaZTGRlZeW6raenJx4eHiQlJT20c/+ReH6Pmzdv8uKLL+ZITGbz9PS0/f/QoUPcunULs9nM5cuXKVas2B8+V7du3ejUqROTJk1izpw5tGvX7r4E508//ZTjvCIiIvZMNZ5ERETEbmXX0MmusfNLf/vb38iXLx/btm2zLUtPT2fPnj222joVK1Zk9+7dOfbbuXNnjtfVq1fn2LFjlC1b9r5/2YkjBwcHGjRoQFRUFIcPH+bMmTNs2LAh17irVasGYCssDeDn50eFChWYNGnSfUmQQ4cOsW7dOoKDg4H/S2ZcvnzZts29Bb+zY05MTMTHx+e+mAsUKADcTbjUqVOH9957jwMHDpAvXz6WLFkC3O1ddW/B7dxUrFjRVlsp27Zt23B1daVkyZK/uu+DmM1m2rdvz4IFC7h06dJ962/evElGRgYVK1YkIyODXbt22db9+OOPfPvtt7nWTfqjfvk7sHPnTipWrJjrttWrV+fkyZN4eXndd6/d3d2Bu8mg4OBghg0bRnBwMB06dMgxK+MvPej+v/766xQoUIDp06ezatUqunbtet82R48ezTV5KSIiYo+UeBIRERG7ZbFYOH78OMeOHcNisdy3vkCBAvTu3ZuwsDBWrVrFsWPH6N69O7dv3yYkJASAXr16cfLkScLCwvj222/57LPPiI2NzXGc8PBwtm/fTt++fTl48CAnT55k2bJltt5WK1as4OOPP+bgwYOcPXuWefPmkZWVha+vb65xe3p6Ur16dbZu3WpbZjKZmDVrFseOHSMwMJDdu3dz7tw5vvzyS5o3b06jRo3o2bMncHco1UsvvcS4ceM4fvw4CQkJvPPOOznO8e9//5uffvqJN954gz179vDdd9+xevVqunTpQmZmJrt27WLMmDHs3buXc+fOER8fzw8//GBLrvj4+HD48GG+/fZbrl69el+PKoA+ffpw/vx5+vXrR1JSEsuWLWP48OG5Fkj/I0aPHk2pUqWoVasW8+bN49ixY5w8eZKYmBj8/Py4efMm5cqVIyAggO7du7N161YOHTpEx44dKVGiBAEBAX/63Nm2bdtGVFQUJ06cYOrUqXz55Zf0798/1207dOjAM888Q0BAAFu2bOH06dNs2rSJ0NBQLly4ANz9PStVqhTvvPMOEydOJDMzk7fffvuB5/fx8WHXrl2cOXOGq1ev2pKRFouF4OBghg4dSrly5e4bEgiwZcsWGjZs+D/fAxERkUdBiScRERGxa25ubri5uT1w/bhx4wgMDKRTp05Ur16dU6dOsXr1alsto9KlS7N48WKWLl1K1apViY6OZsyYMTmO8cILL5CQkMCJEyd45ZVX8PPzIzIy0jbrmoeHB/Hx8fzjH/+gYsWKREdHs3DhQipVqvTAuLp163bf0Kw6deqwc+dOLBYLTZo04dlnn6Vt27YEBASwfPnyHMm1mJgYMjIyePHFFxkwYMB9M8kVL16cbdu2kZmZScOGDalSpQoDBgzAw8MDs9mMm5sbmzdv5vXXX6d8+fK88847fPjhhzRp0gSA7t274+vrS40aNfD09MzRayxbiRIlWLlyJbt376Zq1ar06tWLkJCQ+5Jgf1ThwoXZuXMnHTt2ZNSoUfj5+fHKK6+wcOFCPvjgA1svojlz5vDiiy/SrFkz/P39MQyDlStX3jeU7s8YNGgQe/fuxc/Pj1GjRjFx4sRce9XB3TpSmzdvpnTp0rRq1YqKFSsSEhLCnTt3cHNzY968ebYZ9BwcHChQoADz589n5syZfPPNN7ke8+2338ZisfD888/j6enJuXPnbOtCQkKwWq25zuK4Y8cOrl+/TuvWrf/neyAiIvIomIzfW+FRRERERH631NRUfH19+fzzz3PttQKQlZVFSEgIq1evJiEhwVYHSh4uHx8fBgwYwIABA/I6lFxt2bKF+vXrc/78eby9vXOsa9euHVWrViUiIiKPohMREflj1ONJRERE5CFwcXFh3rx5XL169YHbmM1mZs+eTXh4OFu2bHmE0Yk9SktL48KFC4wYMYI2bdrcl3SyWq1UqVKFt956K48iFBER+ePU40lEREREnir22uMpNjaWkJAQqlWrxldffUWJEiXyOiQREZH/mRJPIiIiIiIiIiLyUGionYiIiIiIiIiIPBRKPImIiIiIiIiIyEOhxJOIiIiIiIiIiDwUSjyJiIiIiIiIiMhDocSTiIiIiIiIiIg8FEo8iYiIiIiIiIjIQ6HEk4iIiIiIiIiIPBRKPImIiIiIiIiIyEOhxJOIiIiIiIiIiDwU/w+A5ImzvnzjywAAAABJRU5ErkJggg==", + "text/plain": [ + "
    " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Grouped bar chart\n", + "metrics = ['mean', 'std']\n", + "x = np.arange(len(context_precision_df['mode'])) # Label locations\n", + "width = 0.2 # Bar width\n", + "fig, ax = plt.subplots(figsize=(12, 6))\n", + "for i, metric in enumerate(metrics):\n", + " ax.bar(x + i * width, context_precision_df[metric], width, label=metric)\n", + "ax.set_xticks(x + width * 1.5)\n", + "ax.set_xticklabels(context_precision_df['mode'] + ' (' + context_precision_df['question_complexity'] + ')', rotation=45, ha='right')\n", + "ax.set_xlabel('Modes (Question Complexity)')\n", + "ax.set_ylabel('Values')\n", + "ax.set_title('Grouped Bar Chart of Context Precision Metrics by Mode and Question Complexity')\n", + "ax.legend(title=\"Metrics\")\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. All modes except entity search + vector score fairly for reasoning questions .\n", + "2. As the metrics calculate context precision we can see for multi context question the score varies for all modes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 5. Context Recall\n", + "\n", + "Context recall measures the extent to which the retrieved context aligns with the annotated answer, treated as the ground truth. It is computed using question, ground truth and the retrieved context, and the values range between 0 and 1, with higher values indicating better performance." + ] + }, + { + "cell_type": "code", + "execution_count": 100, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
    \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
    modequestion_complexitymeanminmaxstd
    0entity search+vectormulti_context0.5619050.1428571.00.310712
    1entity search+vectorreasoning0.2500000.0000001.00.433013
    2entity search+vectorsimple0.5000000.0000001.00.577350
    3fulltextmulti_context0.9523810.7142861.00.116642
    4fulltextreasoning1.0000001.0000001.00.000000
    5fulltextsimple1.0000001.0000001.00.000000
    6global search+vector+fulltextmulti_context0.5119050.1428571.00.341731
    7global search+vector+fulltextreasoning0.1250000.0000000.50.250000
    8global search+vector+fulltextsimple0.6666670.0000001.00.577350
    9graph+vectormulti_context0.9523810.7142861.00.116642
    10graph+vectorreasoning1.0000001.0000001.00.000000
    11graph+vectorsimple1.0000001.0000001.00.000000
    12graph+vector+fulltextmulti_context0.9523810.7142861.00.116642
    13graph+vector+fulltextreasoning1.0000001.0000001.00.000000
    14graph+vector+fulltextsimple1.0000001.0000001.00.000000
    15vectormulti_context0.9107140.7142861.00.138781
    16vectorreasoning1.0000001.0000001.00.000000
    17vectorsimple1.0000001.0000001.00.000000
    \n", + "
    " + ], + "text/plain": [ + " mode question_complexity mean min \\\n", + "0 entity search+vector multi_context 0.561905 0.142857 \n", + "1 entity search+vector reasoning 0.250000 0.000000 \n", + "2 entity search+vector simple 0.500000 0.000000 \n", + "3 fulltext multi_context 0.952381 0.714286 \n", + "4 fulltext reasoning 1.000000 1.000000 \n", + "5 fulltext simple 1.000000 1.000000 \n", + "6 global search+vector+fulltext multi_context 0.511905 0.142857 \n", + "7 global search+vector+fulltext reasoning 0.125000 0.000000 \n", + "8 global search+vector+fulltext simple 0.666667 0.000000 \n", + "9 graph+vector multi_context 0.952381 0.714286 \n", + "10 graph+vector reasoning 1.000000 1.000000 \n", + "11 graph+vector simple 1.000000 1.000000 \n", + "12 graph+vector+fulltext multi_context 0.952381 0.714286 \n", + "13 graph+vector+fulltext reasoning 1.000000 1.000000 \n", + "14 graph+vector+fulltext simple 1.000000 1.000000 \n", + "15 vector multi_context 0.910714 0.714286 \n", + "16 vector reasoning 1.000000 1.000000 \n", + "17 vector simple 1.000000 1.000000 \n", + "\n", + " max std \n", + "0 1.0 0.310712 \n", + "1 1.0 0.433013 \n", + "2 1.0 0.577350 \n", + "3 1.0 0.116642 \n", + "4 1.0 0.000000 \n", + "5 1.0 0.000000 \n", + "6 1.0 0.341731 \n", + "7 0.5 0.250000 \n", + "8 1.0 0.577350 \n", + "9 1.0 0.116642 \n", + "10 1.0 0.000000 \n", + "11 1.0 0.000000 \n", + "12 1.0 0.116642 \n", + "13 1.0 0.000000 \n", + "14 1.0 0.000000 \n", + "15 1.0 0.138781 \n", + "16 1.0 0.000000 \n", + "17 1.0 0.000000 " + ] + }, + "execution_count": 100, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "context_recall_df = eval_df.groupby(['mode', 'question_complexity']).agg({\n", + " 'context_recall': ['mean', 'min', 'max', 'std']\n", + "}).reset_index()\n", + "context_recall_df.columns = ['mode', 'question_complexity', 'mean', 'min', 'max', 'std']\n", + "context_recall_df" + ] + }, + { + "cell_type": "code", + "execution_count": 101, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABJ4AAAJOCAYAAAD2/c3/AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pXeV/AAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzdd1RUV9cG8GdAmiJFQUAkIIoURVTsJTZsYE0ssaEYNTGS2HvvJYrYsfcWa4xdscaYaKwxlti7YkdEBWF/f/jNfRkGFJRhBnx+a7F0zj0zs8/td8+556pEREBERERERERERJTBjPQdABERERERERERZU9MPBERERERERERkU4w8URERERERERERDrBxBMREREREREREekEE09ERERERERERKQTTDwREREREREREZFOMPFEREREREREREQ6wcQTERERERERERHpBBNPRERERERERESkE0w8ERGRolq1aqhWrZq+w9AJNzc31K9fX99hfLJjx46hYsWKyJUrF1QqFU6dOqXvkCgTLF68GCqVCtevX1fKsvr26ubmhvbt22fKd+3fvx8qlQrr1q3LlO/LbNevX4dKpcLixYv1HUq6DR8+HCqVSt9hZIr27dvDzc1N32FkSbre36n3Efv379fZdxB9zph4IiL6f9euXUNoaCiKFCmCnDlzImfOnPDx8UHXrl1x5swZfYdnUNzc3KBSqZQ/c3NzeHh4oE+fPnjy5EmmxvLgwQP07t0bXl5eyJkzJ3LlygV/f3+MHj0az549y9RY1M6dO4fhw4drJAkyQnx8PJo1a4YnT55gypQpWLZsGVxdXd/7Hn3Nn7t372L48OGZkhibNWvWJ19wV6tWTWOdtrCwQPHixREeHo7ExMSMCVRP1NtrQEBAitPnzZuntPvvv/9O9+fran3PitRJFCMjI9y6dUtrenR0NCwsLKBSqRAaGqqHCLO+LVu2oG7dusibNy/Mzc1RpEgRvRx7UpOZ+770io6OxogRI+Dn5wdLS0tYWFigWLFi6NevH+7evavv8AzOypUrER4eru8wiLKFHPoOgIjIEGzZsgUtWrRAjhw50Lp1a/j5+cHIyAgXLlzAhg0bMHv2bFy7du2DF/mfkxIlSqBXr14AgNevX+P48eMIDw/HgQMHcPTo0UyJ4dixYwgMDERMTAzatGkDf39/AMDff/+N8ePH4+DBg9i1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Ebx48QL58+eHkVHq/ZqYeCINd+/ehYuLi77DICIiIiIiIqIs4NatWyhQoECq05l4Ig25c+cG8G7FsbKy0nM0RERERERERGSIoqOj4eLiouQRUsPEE2lQ315nZWXFxBMRERERERERvdeHhunh4OJERERERERERKQTTDwREREREREREZFOMPFEREREREREREQ6wTGeKN0SEhIQHx+v7zCyHRMTExgbG+s7DCIiIiIiIqIMw8QTpZmI4P79+3j27Jm+Q8m2bGxs4Ojo+MHB2YiIiIiIiIiyAiaeKM3USad8+fIhZ86cTI5kIBFBbGwsoqKiAABOTk56joiIiIiIiIjo0zHxZKAOHjyIn3/+GcePH8e9e/ewceNGNG7c+L3v2b9/P3r27Il///0XLi4uGDx4MNq3b58h8SQkJChJp7x582bIZ5ImCwsLAEBUVBTy5cvH2+6IiIiIiIgoy+Pg4gbq5cuX8PPzw8yZM9NU/9q1awgKCkL16tVx6tQpdO/eHR07dsTOnTszJB71mE45c+bMkM+jlKnnL8fQIiIiIiIiouyAPZ4MVL169VCvXr0014+IiEDBggUxefJkAIC3tzd+//13TJkyBXXq1MmwuHh7nW5x/hIREREREVF2wh5P2cSRI0cQEBCgUVanTh0cOXJETxERERERERER0eeOiads4v79+3BwcNAoc3BwQHR0NF69epXq+968eYPo6GiNv8+FSqXCpk2b9B0GERERERERUbbFW+0+c+PGjcOIESP09v3t27fHkiVL8N133yEiIkJjWteuXTFr1iy0a9cOixcv/uBn7d+/H9WrV8fTp09hY2Pzwfr37t2Dra3tR0ZO9Hly6781zXWvjw/SYSQZL61ty2rtIiLd4n4x67Uru+K6+E5Wa1t2lJ2XV3Zumy6xx1M24ejoiAcPHmiUPXjwAFZWVsrT0lIyYMAAPH/+XPm7deuWrkPV4uLigtWrV2v0zHr9+jVWrlyJL774IsO/Ly4uDsC7eWZmZpbhn09ERERERERE7zDxlE1UqFABkZGRGmW7d+9GhQoV3vs+MzMzWFlZafxltlKlSsHFxQUbNmxQyjZs2IAvvvgCJUuWVMoSExMxbtw4FCxYEBYWFvDz88O6desAANevX0f16tUBALa2tlCpVGjfvj0AoFq1aggNDUX37t1hZ2enDLae/Fa727dvo2XLlsiT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T5RmKpUKTk5OyJcvH+Lj4/UdTrZjYmLCnk5ERERERESUrTDxROlmbGzMBAkRERERERERfZDRh6sQERERERERERGlHxNPRERERERERESkE0w8ERERERERERGRTjDxREREREREREREOsHEExERERERERER6QQTT0REREREREREpBNMPBERERERERERkU4w8URERERERERERDrBxBMREREREREREekEE09ERERERERERKQTTDwREREREREREZFOMPFEREREREREREQ6wcQTERERERERERHpBBNPRERERERERESkE0w8ERERERERERGRTjDxREREREREREREOsHEExERERERERER6QQTT0REREREREREpBNMPBERERERERERkU4w8URERERERERERDrBxBMREREREREREekEE09ERERERERERKQTTDwREREREREREZFOMPFEREREREREREQ6wcQTERERERERERHpBBNPRERERERERESkEzn0HQARERER/Y9b/61pqnd9fJCOIyEiIiL6dOzxREREREREREREOsHEExERERERERER6QQTT0REREREREREpBNMPBERERERERERkU4w8URERERERERERDrBxBMREREREREREekEE09ERERERERERKQTTDwREREREREREZFOMPFEREREREREREQ6wcQTERERERERERHpBBNPRERERERERESkE0w8ERERERERERGRTjDxREREREREREREOsHEk4GbOXMm3NzcYG5ujnLlyuHo0aPvrf/s2TN07doVTk5OMDMzQ5EiRbBt27ZMipaIiIiIiIiI6H9y6DsASt2aNWvQs2dPREREoFy5cggPD0edOnVw8eJF5MuXT6t+XFwcatWqhXz58mHdunVwdnbGjRs3YGNjk/nBExEREREREdFnj4knAxYWFoZOnTohJCQEABAREYGtW7di4cKF6N+/v1b9hQsX4smTJ/jjjz9gYmICAHBzc8vMkImIiIiIiIiIFLzVzkDFxcXh+PHjCAgIUMqMjIwQEBCAI0eOpPiezZs3o0KFCujatSscHBxQrFgxjB07FgkJCal+z5s3bxAdHa3xR0RERERERESUEZh4ykC3bt3C7du3lddHjx5F9+7dMXfu3HR/1qNHj5CQkAAHBweNcgcHB9y/fz/F91y9ehXr1q1DQkICtm3bhiFDhmDy5MkYPXp0qt8zbtw4WFtbK38uLi7pjpWIiIiIiIiIKCVMPGWgVq1aYd++fQCA+/fvo1atWjh69CgGDRqEkSNH6vz7ExMTkS9fPsydOxf+/v5o0aIFBg0ahIiIiFTfM2DAADx//lz5u3Xrls7jJCIiIiIiIqLPAxNPGejs2bMoW7YsAOCXX35BsWLF8Mcff2DFihVYvHhxuj7Lzs4OxsbGePDggUb5gwcP4OjomOJ7nJycUKRIERgbGytl3t7euH//PuLi4lJ8j5mZGaysrDT+iIiIiIiIiIgyAhNPGSg+Ph5mZmYAgD179qBhw4YAAC8vL9y7dy9dn2Vqagp/f39ERkYqZYmJiYiMjESFChVSfE+lSpVw+fJlJCYmKmX//fcfnJycYGpqmt7mEBERERERERF9EiaeMlDRokURERGBQ4cOYffu3ahbty4A4O7du8ibN2+6P69nz56YN28elixZgvPnz6NLly54+fKl8pS74OBgDBgwQKnfpUsXPHnyBN26dcN///2HrVu3YuzYsejatWvGNJCIiIiIiIiIKB1y6DuA7GTChAlo0qQJfv75Z7Rr1w5+fn4A3j1tTn0LXnq0aNECDx8+xNChQ3H//n2UKFECO3bsUAYcv3nzJoyM/pc7dHFxwc6dO9GjRw8UL14czs7O6NatG/r165cxDSQiIiIiIiIiSgcmnjJQtWrV8OjRI0RHR8PW1lYp79y5M3LmzPlRnxkaGorQ0NAUp+3fv1+rrEKFCvjzzz8/6ruIDNpw63TUfa67OIiIDAX3i0RERJQF8Fa7DCYiOH78OObMmYMXL14AeDde08cmnoiIiIiIiIiIsir2eMpAN27cQN26dXHz5k28efMGtWrVQu7cuTFhwgS8efMGERER+g6RiIiIiIiIiCjTsMdTBurWrRtKly6Np0+fwsLCQilv0qSJxtPpiIiIiIiIiIg+B+zxlIEOHTqEP/74A6amphrlbm5uuHPnjp6iIiIiIiIiIiLSDyaeMlBiYiISEhK0ym/fvo3cuXPrIaLPj1v/rWmue318kA4jISIiIiIiIiLeapeBateujfDwcOW1SqVCTEwMhg0bhsDAQP0FRkRERERERESkB+zxlIEmT56MOnXqwMfHB69fv0arVq1w6dIl2NnZYdWqVfoOj4iIiIiIiIgoUzHxlIEKFCiA06dPY/Xq1Thz5gxiYmLw7bffonXr1hqDjRMRERERERERfQ6YeMpgOXLkQJs2bfQdBhERERERERGR3jHxlIGWLl363unBwcGZFAkRERERERERkf4x8ZSBunXrpvE6Pj4esbGxMDU1Rc6cOZl4IiIiIiIiIqLPCp9ql4GePn2q8RcTE4OLFy+icuXKHFyciIiIiIiIiD47TDzpmIeHB8aPH6/VG4qIiIiIiIiIKLtj4ikT5MiRA3fv3tV3GEREREREREREmYpjPGWgzZs3a7wWEdy7dw8zZsxApUqV9BQVEREREREREZF+MPGUgRo3bqzxWqVSwd7eHjVq1MDkyZP1ExQRERERERERkZ4w8ZSBEhMT9R0CEREREREREZHBYOKJiIgoG3PrvzXNda+PD9JhJERERET0OWLi6RP17NkzzXXDwsJ0GAkRERERERERkWFh4ukTnTx5Mk31VCqVjiMhIiIiIiIiIjIsTDx9on379uk7BKIsLa23AV0313EgRERERERElOGM9B0AERERERERERFlT+zxlMH+/vtv/PLLL7h58ybi4uI0pm3YsEFPURERERERERERZT72eMpAq1evRsWKFXH+/Hls3LgR8fHx+Pfff7F3715YW1vrOzwiIiIiIiIiokzFxFMGGjt2LKZMmYLffvsNpqammDp1Ki5cuIDmzZvjiy++0Hd4RERERERERESZiomnDHTlyhUEBQUBAExNTfHy5UuoVCr06NEDc+fO1XN0RERERERERESZi4mnDGRra4sXL14AAJydnXH27FkAwLNnzxAbG6vP0IiIiIiIiIiIMh0TTxlAnWD68ssvsXv3bgBAs2bN0K1bN3Tq1AktW7ZEzZo19RkiEREREREREVGm41PtMkDx4sVRpkwZNG7cGM2aNQMADBo0CCYmJvjjjz/w9ddfY/DgwXqOkoiIiIiIiIgoczHxlAEOHDiARYsWYdy4cRgzZgy+/vprdOzYEf3799d3aEREREREREREesNb7TJAlSpVsHDhQty7dw/Tp0/H9evXUbVqVRQpUgQTJkzA/fv39R0iEREREREREVGmY+IpA+XKlQshISE4cOAA/vvvPzRr1gwzZ87EF198gYYNG+o7PCIiIiIiIiKiTMXEk44ULlwYAwcOxODBg5E7d25s3bpV3yEREREREREREWUqjvGkAwcPHsTChQuxfv16GBkZoXnz5vj222/1HRYRERERERERUaZi4imD3L17F4sXL8bixYtx+fJlVKxYEdOmTUPz5s2RK1cufYdHRERERERERJTpmHjKAPXq1cOePXtgZ2eH4OBgdOjQAZ6envoOi4iIiIiIiIhIr5h4ygAmJiZYt24d6tevD2NjY32HQ0RERERERERkEJh4ygCbN2/WdwhERERERERERAaHiSei7Ga4dTrqPtddHERERERERPTZM9J3AERERERERERElD0x8URERERERERERDrBxBMREREREREREekEE09ERERERERERKQTTDwZuJkzZ8LNzQ3m5uYoV64cjh49mqb3rV69GiqVCo0bN9ZtgEREREREREREqWDiyYCtWbMGPXv2xLBhw3DixAn4+fmhTp06iIqKeu/7rl+/jt69e6NKlSqZFCkRERERERERkTYmngxYWFgYOnXqhJCQEPj4+CAiIgI5c+bEwoULU31PQkICWrdujREjRsDd3T0ToyUiIiIiIiIi0sTEk4GKi4vD8ePHERAQoJQZGRkhICAAR44cSfV9I0eORL58+fDtt9+m6XvevHmD6OhojT8iIiIiIiIioozAxJOBevToERISEuDg4KBR7uDggPv376f4nt9//x0LFizAvHnz0vw948aNg7W1tfLn4uLySXETEREREREREakx8ZRNvHjxAm3btsW8efNgZ2eX5vcNGDAAz58/V/5u3bqlwyiJiIiIiIiI6HOSQ98BUMrs7OxgbGyMBw8eaJQ/ePAAjo6OWvWvXLmC69evo0GDBkpZYmIiACBHjhy4ePEiChUqpPU+MzMzmJmZZXD0RERERERERETs8WSwTE1N4e/vj8jISKUsMTERkZGRqFChglZ9Ly8v/PPPPzh16pTy17BhQ1SvXh2nTp3iLXRERERERERElOnY48mA9ezZE+3atUPp0qVRtmxZhIeH4+XLlwgJCQEABAcHw9nZGePGjYO5uTmKFSum8X4bGxsA0ConIiIiIiIiIsoMTDwZsBYtWuDhw4cYOnQo7t+/jxIlSmDHjh3KgOM3b96EkRE7rRERERERERGRYWLiycCFhoYiNDQ0xWn79+9/73sXL16c8QEREREREREREaURu8sQEREREREREZFOMPFEREREREREREQ6wcQTERERERERERHpBBNPRERERERERESkE0w8ERERERERERGRTjDxREREREREREREOsHEExERERERERER6QQTT0REREREREREpBNMPBERERERERERkU7k0HcAREREZCCGW6ej7nPdxUFERERE2QZ7PBERERERERERkU4w8URERERERERERDrBxBMREREREREREekEE09ERERERERERKQTTDwREREREREREZFOMPFEREREREREREQ6wcQTERERERERERHpRA59B0CkN8Ot01H3ue7iICIiIiIiIsqm2OOJiIiIiIiIiIh0goknIiIiIiIiIiLSCSaeiIiIiIiIiIhIJ5h4IiIiIiIiIiIinWDiiYiIiIiIiIiIdIKJJyIiIiIiIiIi0gkmnoiIiIiIiIiISCeYeCIiIiIiIiIiIp1g4omIiIiIiIiIiHSCiSciIiIiIiIiItIJJp6IiIiIiIiIiEgnmHgiIiIiIiIiIiKdYOKJiIiIiIiIiIh0goknIiIiIiIiIiLSCSaeiIiIiIiIiIhIJ3LoOwAi+jC3/lvTXPe6uQ4DISLKioZbp6Puc93FQURERPQZYo8nIiIiIiIiIiLSCSaeiIiIiIiIiIhIJ5h4IiIiIiIiIiIinWDiiYiIiIiIiIiIdIKJJyIiIiIiIiIi0gkmnoiIiIiIiIiISCeYeCIiIiIiIiIiIp1g4omIiIiIiIiIiHSCiScDN3PmTLi5ucHc3BzlypXD0aNHU607b948VKlSBba2trC1tUVAQMB76xMRERERERER6RITTwZszZo16NmzJ4YNG4YTJ07Az88PderUQVRUVIr19+/fj5YtW2Lfvn04cuQIXFxcULt2bdy5cyeTIyciIiIiIiIiYuLJoIWFhaFTp04ICQmBj48PIiIikDNnTixcuDDF+itWrMAPP/yAEiVKwMvLC/Pnz0diYiIiIyMzOXIiIiIiIiIiIiaeDFZcXByOHz+OgIAApczIyAgBAQE4cuRImj4jNjYW8fHxyJMnj67CJCIiIiIiIiJKVQ59B0Ape/ToERISEuDg4KBR7uDggAsXLqTpM/r164f8+fNrJK+Se/PmDd68eaO8jo6O/riAiYiIiIiIiIiSYY+nbGr8+PFYvXo1Nm7cCHNz81TrjRs3DtbW1sqfi4tLJkZJRERERERERNkZE08Gys7ODsbGxnjw4IFG+YMHD+Do6Pje906aNAnjx4/Hrl27ULx48ffWHTBgAJ4/f6783bp165NjJyIiIiIiIiICmHgyWKampvD399cYGFw9UHiFChVSfd/EiRMxatQo7NixA6VLl/7g95iZmcHKykrjj4iIiIiIiIgoI3CMJwPWs2dPtGvXDqVLl0bZsmURHh6Oly9fIiQkBAAQHBwMZ2dnjBs3DgAwYcIEDB06FCtXroSbmxvu378PALC0tISlpaXe2kFEREREREREnycmngxYixYt8PDhQwwdOhT3799HiRIlsGPHDmXA8Zs3b8LI6H+d1mbPno24uDg0bdpU43OGDRuG4cOHZ2boRERERERERERMPBm60NBQhIaGpjht//79Gq+vX7+u+4CIiIiIiIiIiNKIYzwREREREREREZFOMPFEREREREREREQ6wcQTERERERERERHpBBNPRERERERERESkE0w8ERERERERERGRTjDxREREREREREREOsHEExERERERERER6QQTT0REREREREREpBNMPBERERERERERkU4w8URERERERERERDqRQ98BEBEREREREdF7DLdOR93nuouD6COwxxMREREREREREekEE09ERERERERERKQTTDwREREREREREZFOcIwnIiIiynLc+m9Nc93r5joMhIiIiIjeiz2eiIiIiIiIiIhIJ9jjiYhI3/iUEiIiTdwvkqHgukhE9MnY44mIiIiIiIiIiHSCiSciIiIiIiIiItIJJp6IiIiIiIiIiEgnmHgiIiIiIiIiIiKdYOKJiIiIiIiIiIh0goknIiIiIiIiIiLSCSaeiIiIiIiIiIhIJ5h4IiIiIiIiIiIinWDiiYiIiIiIiIiIdIKJJyIiIiIiIiIi0gkmnoiIiIiIiIiISCeYeCIiIiIiIiIiIp1g4omIiIiIiIiIiHSCiSciIiIiIiIiItIJJp6IiIiIiIiIiEgnmHgiIiIiIiIiIiKdYOKJiIiIiIiIiIh0goknIiIiIiIiIiLSCSaeiIiIiIiIiIhIJ5h4IiIiIiIiIiIinWDiiYiIiIiIiIiIdIKJJyIiIiIiIiIi0gkmnoiIiIiIiIiISCeYeCIiIiIiIiIiIp1g4omIiIiIiIiIiHSCiSciIiIiIiIiItIJJp4M3MyZM+Hm5gZzc3OUK1cOR48efW/9tWvXwsvLC+bm5vD19cW2bdsyKVIiIiIiIiIiIk1MPBmwNWvWoGfPnhg2bBhOnDgBPz8/1KlTB1FRUSnW/+OPP9CyZUt8++23OHnyJBo3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AAwcOJCjR48SERHBt99+y0cffUR8fHyR40RGRrJ582aGDBnC3r17OXr0KMuWLbP1tlqxYgXvv/8+e/fu5cSJEyxYsICCggL8/f2LjdvT05OGDRuyceNG2zKTycScOXM4dOgQwcHBbN++nZMnT/LZZ5/x3HPP0bp1awYMGABcG0r12GOPMXHiRA4fPkxKSgqvv/56kXP8+9//5ueff+b5559nx44dfPfddyQnJ9O7d2/y8/PZtm0b48ePZ+fOnZw8eZKkpCR+/PFHW3LFz8+P/fv38+2333Lu3LkbelQBDB48mFOnTvHiiy+SlpbGsmXLGDVqVLEF0v+McePG4ePjQ5MmTViwYAGHDh3i6NGjxMXFERAQwKVLl6hRowZBQUH069ePjRs3sm/fPnr06EGVKlUICgr6y+cutGnTJmJiYjhy5AjTp0/ns88+46WXXip22+7du/PAAw8QFBTEhg0bSE9PZ/369YSHh3P69Gng2u+Zj48Pr7/+OpMnTyY/P59XXnnlpuf38/Nj27ZtHD9+nHPnztmSkRaLhdDQUF577TVq1Khxw5BAgA0bNtCqVav/+R6IiIjcCUo8iYiIiF1zc3PDzc3tpusnTpxIcHAwPXv2pGHDhhw7dozk5GRbLSNfX18WL17M0qVLqV+/PrGxsYwfP77IMR555BFSUlI4cuQITzzxBAEBAURHR9tmXfPw8CApKYl//OMf1K5dm9jYWD7++GPq1Klz07j69u17w9CsZs2asXXrViwWC23btuXBBx+kS5cuBAUFsXz58iLJtbi4OPLy8nj00UcZOnToDTPJVa5cmU2bNpGfn0+rVq2oV68eQ4cOxcPDA7PZjJubG9988w3PPPMMNWvW5PXXX+fdd9+lbdu2APTr1w9/f38aNWqEp6dnkV5jhapUqcLKlSvZvn079evXZ+DAgYSFhd2QBPuzypcvz9atW+nRowdjx44lICCAJ554go8//pi3337b1oto3rx5PProozz77LMEBgZiGAYrV668YSjdXzF8+HB27txJQEAAY8eOZfLkycX2qoNrdaS++eYbfH196dixI7Vr1yYsLIyrV6/i5ubGggULbDPoOTg4UKZMGRYuXMjs2bP58ssviz3mK6+8gsVi4eGHH8bT05OTJ0/a1oWFhWG1WoudxXHLli1cuHCBTp06/c/3QERE5E4wGX+0wqOIiIiI/GHZ2dn4+/vzySefFNtrBaCgoICwsDCSk5NJSUmx1YGS28vPz4+hQ4cydOjQkg6lWBs2bODpp5/m1KlTeHt7F1nXtWtX6tevT1RUVAlFJyIi8ueox5OIiIjIbeDi4sKCBQs4d+7cTbcxm83MnTuXyMhINmzYcAejE3uUk5PD6dOnGT16NJ07d74h6WS1WqlXrx4vv/xyCUUoIiLy56nHk4iIiIjcV+y1x1N8fDxhYWE0aNCAzz//nCpVqpR0SCIiIv8zJZ5EREREREREROS20FA7ERERERERERG5LZR4EhERERERERGR20KJJxERERERERERuS2UeBIRERERERERkdtCiScREREREREREbktlHgSEREREREREZHbQoknERERERERERG5LZR4EhERERERERGR20KJJxERERERERERuS3+H2VEjJd2TLS4AAAAAElFTkSuQmCC", + "text/plain": [ + "
    " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Grouped bar chart\n", + "metrics = ['mean', 'std']\n", + "x = np.arange(len(context_recall_df['mode'])) # Label locations\n", + "width = 0.2 # Bar width\n", + "fig, ax = plt.subplots(figsize=(12, 6))\n", + "for i, metric in enumerate(metrics):\n", + " ax.bar(x + i * width, context_recall_df[metric], width, label=metric)\n", + "ax.set_xticks(x + width * 1.5)\n", + "ax.set_xticklabels(context_recall_df['mode'] + ' (' + context_recall_df['question_complexity'] + ')', rotation=45, ha='right')\n", + "ax.set_xlabel('Modes (Question Complexity)')\n", + "ax.set_ylabel('Values')\n", + "ax.set_title('Grouped Bar Chart of Context Recall Metrics by Mode and Question Complexity')\n", + "ax.legend(title=\"Metrics\")\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. \"entity search + vector\" and \"global search + vector + fulltext \" modes are performing poor for all question complexities. other modes have scored perfect score for context recall." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "myenv312", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.14" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From b663ff43572dabb154cee4ec38ed6bf6ba435ab5 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Mon, 30 Sep 2024 04:59:06 +0000 Subject: [PATCH 145/292] deleted unused file --- frontend/src/HOC/SettingModalHOC.tsx | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 frontend/src/HOC/SettingModalHOC.tsx diff --git a/frontend/src/HOC/SettingModalHOC.tsx b/frontend/src/HOC/SettingModalHOC.tsx deleted file mode 100644 index 24d84bbff..000000000 --- a/frontend/src/HOC/SettingModalHOC.tsx +++ /dev/null @@ -1,28 +0,0 @@ -// import React from 'react'; -// import { SettingsModalProps } from '../types'; -// import SettingsModal from '../components/Popups/Settings/SettingModal'; - -// const SettingModalHOC: React.FC = ({ -// openTextSchema, -// open, -// onClose, -// isSchema, -// settingView, -// setIsSchema, -// onContinue, -// onClear, -// }) => { -// return ( -// -// ); -// }; -// export default SettingModalHOC; From 7c653443fcddd50ce93979428a0491b0a4c40fd4 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Mon, 30 Sep 2024 05:32:28 +0000 Subject: [PATCH 146/292] code optimization using memo --- .../src/components/ChatBot/ChatInfoModal.tsx | 8 ++- .../ChatBot/ExpandedChatButtonContainer.tsx | 4 +- frontend/src/components/Dropdown.tsx | 4 +- frontend/src/components/Layout/Header.tsx | 14 +++-- frontend/src/components/Layout/SideNav.tsx | 55 +++++++------------ .../Popups/DeletePopUp/DeletePopUp.tsx | 5 +- .../LargeFilePopUp/ConfirmationDialog.tsx | 5 +- .../Popups/RetryConfirmation/Index.tsx | 4 +- frontend/src/components/QuickStarter.tsx | 12 +--- frontend/src/components/UI/TipWrapper.tsx | 20 +++++++ frontend/src/context/UserMessages.tsx | 7 +-- frontend/src/types.ts | 1 + frontend/src/utils/Constants.ts | 6 +- 13 files changed, 75 insertions(+), 70 deletions(-) create mode 100644 frontend/src/components/UI/TipWrapper.tsx diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index d4fb89af9..894833884 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -100,11 +100,13 @@ const ChatInfoModal: React.FC = ({ if (response.data.status === 'Failure') { throw new Error(response.data.error); } - const nodesData = response?.data?.data?.nodes.map((f: Node) => f) + const nodesData = response?.data?.data?.nodes + .map((f: Node) => f) .filter((node: ExtendedNode) => node.labels.length === 1); const nodeIds = new Set(nodesData.map((node: any) => node.element_id)); - const relationshipsData = response?.data?.data?.relationships.map((f: Relationship) => f) - .filter((rel: any) => nodeIds.has(rel.end_node_element_id) && nodeIds.has(rel.start_node_element_id));; + const relationshipsData = response?.data?.data?.relationships + .map((f: Relationship) => f) + .filter((rel: any) => nodeIds.has(rel.end_node_element_id) && nodeIds.has(rel.start_node_element_id)); const communitiesData = response?.data?.data?.community_data; const chunksData = response?.data?.data?.chunk_data; diff --git a/frontend/src/components/ChatBot/ExpandedChatButtonContainer.tsx b/frontend/src/components/ChatBot/ExpandedChatButtonContainer.tsx index 465687c4b..44bddc805 100644 --- a/frontend/src/components/ChatBot/ExpandedChatButtonContainer.tsx +++ b/frontend/src/components/ChatBot/ExpandedChatButtonContainer.tsx @@ -4,7 +4,7 @@ import { Box, IconButton } from '@neo4j-ndl/react'; import { IconProps } from '../../types'; import { IconButtonWithToolTip } from '../UI/IconButtonToolTip'; import { tooltips } from '../../utils/Constants'; -import { useState } from 'react'; +import { memo, useState } from 'react'; import { RiChatSettingsLine } from 'react-icons/ri'; const ExpandedChatButtonContainer: React.FC = ({ closeChatBot, deleteOnClick, messages }) => { @@ -51,4 +51,4 @@ const ExpandedChatButtonContainer: React.FC = ({ closeChatBot, delete ); }; -export default ExpandedChatButtonContainer; +export default memo(ExpandedChatButtonContainer); diff --git a/frontend/src/components/Dropdown.tsx b/frontend/src/components/Dropdown.tsx index ba949aec0..cdf658824 100644 --- a/frontend/src/components/Dropdown.tsx +++ b/frontend/src/components/Dropdown.tsx @@ -1,6 +1,6 @@ import { Dropdown, Tip } from '@neo4j-ndl/react'; import { OptionType, ReusableDropdownProps } from '../types'; -import { useMemo, useReducer } from 'react'; +import { memo, useMemo, useReducer } from 'react'; import { capitalize } from '../utils/Utils'; const DropdownComponent: React.FC = ({ @@ -68,4 +68,4 @@ const DropdownComponent: React.FC = ({ ); }; -export default DropdownComponent; +export default memo(DropdownComponent); diff --git a/frontend/src/components/Layout/Header.tsx b/frontend/src/components/Layout/Header.tsx index acf62eefa..752c31660 100644 --- a/frontend/src/components/Layout/Header.tsx +++ b/frontend/src/components/Layout/Header.tsx @@ -7,12 +7,15 @@ import { InformationCircleIconOutline, } from '@neo4j-ndl/react/icons'; import { Typography } from '@neo4j-ndl/react'; -import { useCallback, useEffect } from 'react'; +import { memo, useCallback, useContext, useEffect } from 'react'; import { IconButtonWithToolTip } from '../UI/IconButtonToolTip'; import { tooltips } from '../../utils/Constants'; import { useFileContext } from '../../context/UsersFiles'; +import { ThemeWrapperContext } from '../../context/ThemeWrapper'; + +function Header() { + const { colorMode, toggleColorMode } = useContext(ThemeWrapperContext); -export default function Header({ themeMode, toggleTheme }: { themeMode: string; toggleTheme: () => void }) { const handleURLClick = useCallback((url: string) => { window.open(url, '_blank'); }, []); @@ -38,7 +41,7 @@ export default function Header({ themeMode, toggleTheme }: { themeMode: string;
    Neo4j Logo @@ -75,10 +78,10 @@ export default function Header({ themeMode, toggleTheme }: { themeMode: string; text={tooltips.theme} clean size='large' - onClick={toggleTheme} + onClick={toggleColorMode} placement='left' > - {themeMode === 'dark' ? ( + {colorMode === 'dark' ? ( @@ -95,3 +98,4 @@ export default function Header({ themeMode, toggleTheme }: { themeMode: string;
    ); } +export default memo(Header); diff --git a/frontend/src/components/Layout/SideNav.tsx b/frontend/src/components/Layout/SideNav.tsx index 526150db4..e07979405 100644 --- a/frontend/src/components/Layout/SideNav.tsx +++ b/frontend/src/components/Layout/SideNav.tsx @@ -23,6 +23,7 @@ import S3Component from '../DataSources/AWS/S3Bucket'; import WebButton from '../DataSources/Web/WebButton'; import DropZoneForSmallLayouts from '../DataSources/Local/DropZoneForSmallLayouts'; import { useCredentials } from '../../context/UserCredentials'; +import TipWrapper from '../UI/TipWrapper'; const SideNav: React.FC = ({ position, @@ -101,12 +102,9 @@ const SideNav: React.FC = ({ - - - - {tooltips.sources} - + + + } /> )} @@ -115,12 +113,9 @@ const SideNav: React.FC = ({ - - - - {tooltips.chat} - + + + } /> )} @@ -128,48 +123,36 @@ const SideNav: React.FC = ({ {!largedesktops && position === 'left' && !isReadOnlyUser && ( - - - - Local files - + + + } /> )} {!largedesktops && APP_SOURCES.includes('gcs') && position === 'left' && !isReadOnlyUser && ( - - - - GCS Files - + + + } /> )} {!largedesktops && APP_SOURCES.includes('s3') && position === 'left' && !isReadOnlyUser && ( - - - - S3 Files - + + + } /> )} {!largedesktops && APP_SOURCES.includes('web') && position === 'left' && !isReadOnlyUser && ( - - - - Web Sources - + + + } > )} diff --git a/frontend/src/components/Popups/DeletePopUp/DeletePopUp.tsx b/frontend/src/components/Popups/DeletePopUp/DeletePopUp.tsx index 1b1bd58c8..cbe69c492 100644 --- a/frontend/src/components/Popups/DeletePopUp/DeletePopUp.tsx +++ b/frontend/src/components/Popups/DeletePopUp/DeletePopUp.tsx @@ -1,6 +1,6 @@ import { Button, Checkbox, Dialog } from '@neo4j-ndl/react'; -import { useState } from 'react'; -export default function DeletePopUp({ +import { memo, useState } from 'react'; +function DeletePopUp({ open, no_of_files, deleteHandler, @@ -55,3 +55,4 @@ export default function DeletePopUp({ ); } +export default memo(DeletePopUp); diff --git a/frontend/src/components/Popups/LargeFilePopUp/ConfirmationDialog.tsx b/frontend/src/components/Popups/LargeFilePopUp/ConfirmationDialog.tsx index 8d04467ff..08991c44b 100644 --- a/frontend/src/components/Popups/LargeFilePopUp/ConfirmationDialog.tsx +++ b/frontend/src/components/Popups/LargeFilePopUp/ConfirmationDialog.tsx @@ -1,10 +1,10 @@ import { Button, Dialog, Typography } from '@neo4j-ndl/react'; import { CustomFile } from '../../../types'; import LargeFilesAlert from './LargeFilesAlert'; -import { useEffect, useState } from 'react'; +import { memo, useEffect, useState } from 'react'; import { useFileContext } from '../../../context/UsersFiles'; -export default function ConfirmationDialog({ +function ConfirmationDialog({ largeFiles, open, onClose, @@ -111,3 +111,4 @@ export default function ConfirmationDialog({ ); } +export default memo(ConfirmationDialog); diff --git a/frontend/src/components/Popups/RetryConfirmation/Index.tsx b/frontend/src/components/Popups/RetryConfirmation/Index.tsx index d7b160e8e..a510352aa 100644 --- a/frontend/src/components/Popups/RetryConfirmation/Index.tsx +++ b/frontend/src/components/Popups/RetryConfirmation/Index.tsx @@ -4,8 +4,9 @@ import { useFileContext } from '../../../context/UsersFiles'; import { capitalize } from '../../../utils/Utils'; import { BannerAlertProps } from '../../../types'; import ButtonWithToolTip from '../../UI/ButtonWithToolTip'; +import { memo } from 'react'; -export default function RetryConfirmationDialog({ +function RetryConfirmationDialog({ open, onClose, fileId, @@ -82,3 +83,4 @@ export default function RetryConfirmationDialog({ ); } +export default memo(RetryConfirmationDialog); \ No newline at end of file diff --git a/frontend/src/components/QuickStarter.tsx b/frontend/src/components/QuickStarter.tsx index db2cba7e7..1a4e169d2 100644 --- a/frontend/src/components/QuickStarter.tsx +++ b/frontend/src/components/QuickStarter.tsx @@ -1,6 +1,5 @@ import Header from './Layout/Header'; import React, { useState } from 'react'; -import { ThemeWrapperContext } from '../context/ThemeWrapper'; import PageLayout from './Layout/PageLayout'; import { FileContextProvider } from '../context/UsersFiles'; import UserCredentialsWrapper from '../context/UserCredentials'; @@ -8,16 +7,7 @@ import AlertContextWrapper from '../context/Alert'; import { MessageContextWrapper } from '../context/UserMessages'; const QuickStarter: React.FunctionComponent = () => { - const themeUtils = React.useContext(ThemeWrapperContext); - const [themeMode, setThemeMode] = useState(themeUtils.colorMode); const [showSettingsModal, setshowSettingsModal] = useState(false); - - const toggleColorMode = () => { - setThemeMode((prevThemeMode) => { - return prevThemeMode === 'light' ? 'dark' : 'light'; - }); - themeUtils.toggleColorMode(); - }; const openSettingsModal = () => { setshowSettingsModal(true); }; @@ -30,7 +20,7 @@ const QuickStarter: React.FunctionComponent = () => { -
    +
    + {children} + {tooltip} + + ); +} +export default TipWrapper; diff --git a/frontend/src/context/UserMessages.tsx b/frontend/src/context/UserMessages.tsx index 0e7b7abde..e586621f9 100644 --- a/frontend/src/context/UserMessages.tsx +++ b/frontend/src/context/UserMessages.tsx @@ -1,14 +1,11 @@ import { createContext, useState, useContext, FC } from 'react'; import { MessagesContextProviderProps, Messages, MessageContextType } from '../types'; -import chatbotmessages from '../assets/ChatbotMessages.json'; -import { getDateTime } from '../utils/Utils'; +import { getDefaultMessage } from '../utils/Constants'; const MessageContext = createContext(undefined); const MessageContextWrapper: FC = ({ children }) => { - const [messages, setMessages] = useState([ - { ...chatbotmessages.listMessages[1], datetime: getDateTime() }, - ]); + const [messages, setMessages] = useState(getDefaultMessage); const [clearHistoryData, setClearHistoryData] = useState(false); const value: MessageContextType = { diff --git a/frontend/src/types.ts b/frontend/src/types.ts index f407ca350..5dc09f418 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -738,3 +738,4 @@ export interface FileContextType { postProcessingVal: boolean; setPostProcessingVal: Dispatch>; } +export declare type Side = 'top' | 'right' | 'bottom' | 'left'; diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index daf3ef0f2..a9a41c0a2 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -1,6 +1,7 @@ import { NvlOptions } from '@neo4j-nvl/base'; import { GraphType, OptionType } from '../types'; -import { getDescriptionForChatMode } from './Utils'; +import { getDateTime, getDescriptionForChatMode } from './Utils'; +import chatbotmessages from '../assets/ChatbotMessages.json'; export const document = `+ [docs]`; @@ -309,3 +310,6 @@ export const connectionLabels = { greenStroke: 'green', redStroke: 'red', }; +export const getDefaultMessage = () => { + return [{ ...chatbotmessages.listMessages[1], datetime: getDateTime() }]; +}; From c69b70884b64f6f0cabcdb02dd9f692ad1bf40cd Mon Sep 17 00:00:00 2001 From: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:54:50 +0000 Subject: [PATCH 147/292] Added elapsed_time on each api and getiing time per_entity --- backend/score.py | 81 +++++++++++++++++++++++++++++++++++---------- backend/src/main.py | 6 ++-- 2 files changed, 68 insertions(+), 19 deletions(-) diff --git a/backend/score.py b/backend/score.py index a9e8e0b93..eba6c3a00 100644 --- a/backend/score.py +++ b/backend/score.py @@ -90,6 +90,7 @@ async def create_source_knowledge_graph_url( ): try: + start = time.time() if source_url is not None: source = source_url else: @@ -115,9 +116,12 @@ async def create_source_knowledge_graph_url( return create_api_response('Failed',message='source_type is other than accepted source') message = f"Source Node created successfully for source type: {source_type} and source: {source}" - json_obj = {'api_name':'url_scan','db_url':uri,'url_scanned_file':lst_file_name, 'source_url':source_url, 'wiki_query':wiki_query, 'logging_time': formatted_time(datetime.now(timezone.utc))} + end = time.time() + elapsed_time = end - start + json_obj = {'api_name':'url_scan','db_url':uri,'url_scanned_file':lst_file_name, 'source_url':source_url, 'wiki_query':wiki_query, 'logging_time': formatted_time(datetime.now(timezone.utc)), 'elapsed_api_time':f'{elapsed_time:.2f}'} logger.log_struct(json_obj, "INFO") - return create_api_response("Success",message=message,success_count=success_count,failed_count=failed_count,file_name=lst_file_name) + result ={'elapsed_api_time' : f'{elapsed_time:.2f}'} + return create_api_response("Success",message=message,success_count=success_count,failed_count=failed_count,file_name=lst_file_name,data=result) except Exception as e: error_message = str(e) message = f" Unable to create source node for source type: {source_type} and source: {source}" @@ -198,7 +202,7 @@ async def extract_knowledge_graph_from_file( extract_graph_from_file_gcs, uri, userName, password, database, model, gcs_project_id, gcs_bucket_name, gcs_bucket_folder, gcs_blob_filename, access_token, file_name, allowedNodes, allowedRelationship, retry_condition) else: return create_api_response('Failed',message='source_type is other than accepted source') - + extract_api_time = time.time() - start_time if result is not None: result['db_url'] = uri result['api_name'] = 'extract' @@ -206,8 +210,8 @@ async def extract_knowledge_graph_from_file( result['wiki_query'] = wiki_query result['source_type'] = source_type result['logging_time'] = formatted_time(datetime.now(timezone.utc)) + result['elapsed_api_time'] = f'{extract_api_time:.2f}' logger.log_struct(result, "INFO") - extract_api_time = time.time() - start_time logging.info(f"extraction completed in {extract_api_time:.2f} seconds for file name {file_name}") return create_api_response('Success', data=result, file_source= source_type) except Exception as e: @@ -237,13 +241,16 @@ async def get_source_list(uri:str, userName:str, password:str, database:str=None Calls 'get_source_list_from_graph' which returns list of sources which already exist in databse """ try: + start = time.time() decoded_password = decode_password(password) if " " in uri: uri = uri.replace(" ","+") result = await asyncio.to_thread(get_source_list_from_graph,uri,userName,decoded_password,database) - json_obj = {'api_name':'sources_list','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} + end = time.time() + elapsed_time = end - start + json_obj = {'api_name':'sources_list','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc)), 'elapsed_api_time':f'{elapsed_time:.2f}'} logger.log_struct(json_obj, "INFO") - return create_api_response("Success",data=result) + return create_api_response("Success",data=result, message=f"Total elapsed API time {elapsed_time:.2f}") except Exception as e: job_status = "Failed" message="Unable to fetch source list" @@ -307,7 +314,7 @@ async def chat_bot(uri=Form(),model=Form(None),userName=Form(), password=Form(), logging.info(f"Total Response time is {total_call_time:.2f} seconds") result["info"]["response_time"] = round(total_call_time, 2) - json_obj = {'api_name':'chat_bot','db_url':uri,'session_id':session_id, 'logging_time': formatted_time(datetime.now(timezone.utc))} + json_obj = {'api_name':'chat_bot','db_url':uri,'session_id':session_id, 'logging_time': formatted_time(datetime.now(timezone.utc)), 'elapsed_api_time':f'{total_call_time:.2f}'} logger.log_struct(json_obj, "INFO") return create_api_response('Success',data=result) @@ -323,10 +330,13 @@ async def chat_bot(uri=Form(),model=Form(None),userName=Form(), password=Form(), @app.post("/chunk_entities") async def chunk_entities(uri=Form(),userName=Form(), password=Form(), database=Form(), nodedetails=Form(None),entities=Form(),mode=Form()): try: + start = time.time() result = await asyncio.to_thread(get_entities_from_chunkids,uri=uri, username=userName, password=password, database=database,nodedetails=nodedetails,entities=entities,mode=mode) - json_obj = {'api_name':'chunk_entities','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} + end = time.time() + elapsed_time = end - start + json_obj = {'api_name':'chunk_entities','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc)), 'elapsed_api_time':f'{elapsed_time:.2f}'} logger.log_struct(json_obj, "INFO") - return create_api_response('Success',data=result) + return create_api_response('Success',data=result,message=f"Total elapsed API time {elapsed_time:.2f}") except Exception as e: job_status = "Failed" message="Unable to extract entities from chunk ids" @@ -345,7 +355,8 @@ async def graph_query( document_names: str = Form(None), ): try: - print(document_names) + # print(document_names) + start = time.time() result = await asyncio.to_thread( get_graph_results, uri=uri, @@ -354,9 +365,11 @@ async def graph_query( database=database, document_names=document_names ) - json_obj = {'api_name':'graph_query','db_url':uri,'document_names':document_names, 'logging_time': formatted_time(datetime.now(timezone.utc))} + end = time.time() + elapsed_time = end - start + json_obj = {'api_name':'graph_query','db_url':uri,'document_names':document_names, 'logging_time': formatted_time(datetime.now(timezone.utc)), 'elapsed_api_time':f'{elapsed_time:.2f}'} logger.log_struct(json_obj, "INFO") - return create_api_response('Success', data=result) + return create_api_response('Success', data=result,message=f"Total elapsed API time {elapsed_time:.2f}") except Exception as e: job_status = "Failed" message = "Unable to get graph query response" @@ -385,10 +398,14 @@ async def clear_chat_bot(uri=Form(),userName=Form(), password=Form(), database=F @app.post("/connect") async def connect(uri=Form(), userName=Form(), password=Form(), database=Form()): try: + start = time.time() graph = create_graph_database_connection(uri, userName, password, database) result = await asyncio.to_thread(connection_check_and_get_vector_dimensions, graph, database) - json_obj = {'api_name':'connect','db_url':uri,'status':result, 'count':1, 'logging_time': formatted_time(datetime.now(timezone.utc))} + end = time.time() + elapsed_time = end - start + json_obj = {'api_name':'connect','db_url':uri,'status':result, 'count':1, 'logging_time': formatted_time(datetime.now(timezone.utc)), 'elapsed_api_time':f'{elapsed_time:.2f}'} logger.log_struct(json_obj, "INFO") + result['elapsed_api_time'] = f'{elapsed_time:.2f}' return create_api_response('Success',data=result) except Exception as e: job_status = "Failed" @@ -402,10 +419,14 @@ async def upload_large_file_into_chunks(file:UploadFile = File(...), chunkNumber originalname=Form(None), model=Form(None), uri=Form(), userName=Form(), password=Form(), database=Form()): try: + start = time.time() graph = create_graph_database_connection(uri, userName, password, database) result = await asyncio.to_thread(upload_file, graph, model, file, chunkNumber, totalChunks, originalname, uri, CHUNK_DIR, MERGED_DIR) - json_obj = {'api_name':'upload','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} + end = time.time() + elapsed_time = end - start + json_obj = {'api_name':'upload','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc)), 'elapsed_api_time':f'{elapsed_time:.2f}'} logger.log_struct(json_obj, "INFO") + result['elapsed_api_time'] = f'{elapsed_time:.2f}' if int(chunkNumber) == int(totalChunks): return create_api_response('Success',data=result, message='Source Node Created Successfully') else: @@ -423,12 +444,15 @@ async def upload_large_file_into_chunks(file:UploadFile = File(...), chunkNumber @app.post("/schema") async def get_structured_schema(uri=Form(), userName=Form(), password=Form(), database=Form()): try: + start = time.time() graph = create_graph_database_connection(uri, userName, password, database) result = await asyncio.to_thread(get_labels_and_relationtypes, graph) + end = time.time() + elapsed_time = end - start logging.info(f'Schema result from DB: {result}') - json_obj = {'api_name':'schema','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} + json_obj = {'api_name':'schema','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc)), 'elapsed_api_time':f'{elapsed_time:.2f}'} logger.log_struct(json_obj, "INFO") - return create_api_response('Success', data=result) + return create_api_response('Success', data=result,message=f"Total elapsed API time {elapsed_time:.2f}") except Exception as e: message="Unable to get the labels and relationtypes from neo4j database" error_message = str(e) @@ -490,12 +514,15 @@ async def delete_document_and_entities(uri=Form(), source_types=Form(), deleteEntities=Form()): try: + start = time.time() graph = create_graph_database_connection(uri, userName, password, database) graphDb_data_Access = graphDBdataAccess(graph) result, files_list_size = await asyncio.to_thread(graphDb_data_Access.delete_file_from_graph, filenames, source_types, deleteEntities, MERGED_DIR, uri) # entities_count = result[0]['deletedEntities'] if 'deletedEntities' in result[0] else 0 message = f"Deleted {files_list_size} documents with entities from database" - json_obj = {'api_name':'delete_document_and_entities','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} + end = time.time() + elapsed_time = end - start + json_obj = {'api_name':'delete_document_and_entities','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc)), 'elapsed_api_time':f'{elapsed_time:.2f}'} logger.log_struct(json_obj, "INFO") return create_api_response('Success',message=message) except Exception as e: @@ -574,9 +601,14 @@ async def populate_graph_schema(input_text=Form(None), model=Form(None), is_sche @app.post("/get_unconnected_nodes_list") async def get_unconnected_nodes_list(uri=Form(), userName=Form(), password=Form(), database=Form()): try: + start = time.time() graph = create_graph_database_connection(uri, userName, password, database) graphDb_data_Access = graphDBdataAccess(graph) nodes_list, total_nodes = graphDb_data_Access.list_unconnected_nodes() + end = time.time() + elapsed_time = end - start + json_obj = {'api_name':'get_unconnected_nodes_list','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc)), 'elapsed_api_time':f'{elapsed_time:.2f}'} + logger.log_struct(json_obj, "INFO") return create_api_response('Success',data=nodes_list,message=total_nodes) except Exception as e: job_status = "Failed" @@ -590,9 +622,14 @@ async def get_unconnected_nodes_list(uri=Form(), userName=Form(), password=Form( @app.post("/delete_unconnected_nodes") async def delete_orphan_nodes(uri=Form(), userName=Form(), password=Form(), database=Form(),unconnected_entities_list=Form()): try: + start = time.time() graph = create_graph_database_connection(uri, userName, password, database) graphDb_data_Access = graphDBdataAccess(graph) result = graphDb_data_Access.delete_unconnected_nodes(unconnected_entities_list) + end = time.time() + elapsed_time = end - start + json_obj = {'api_name':'delete_unconnected_nodes','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc)), 'elapsed_api_time':f'{elapsed_time:.2f}'} + logger.log_struct(json_obj, "INFO") return create_api_response('Success',data=result,message="Unconnected entities delete successfully") except Exception as e: job_status = "Failed" @@ -606,9 +643,14 @@ async def delete_orphan_nodes(uri=Form(), userName=Form(), password=Form(), data @app.post("/get_duplicate_nodes") async def get_duplicate_nodes(uri=Form(), userName=Form(), password=Form(), database=Form()): try: + start = time.time() graph = create_graph_database_connection(uri, userName, password, database) graphDb_data_Access = graphDBdataAccess(graph) nodes_list, total_nodes = graphDb_data_Access.get_duplicate_nodes_list() + end = time.time() + elapsed_time = end - start + json_obj = {'api_name':'get_duplicate_nodes','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc)), 'elapsed_api_time':f'{elapsed_time:.2f}'} + logger.log_struct(json_obj, "INFO") return create_api_response('Success',data=nodes_list, message=total_nodes) except Exception as e: job_status = "Failed" @@ -622,9 +664,14 @@ async def get_duplicate_nodes(uri=Form(), userName=Form(), password=Form(), data @app.post("/merge_duplicate_nodes") async def merge_duplicate_nodes(uri=Form(), userName=Form(), password=Form(), database=Form(),duplicate_nodes_list=Form()): try: + start = time.time() graph = create_graph_database_connection(uri, userName, password, database) graphDb_data_Access = graphDBdataAccess(graph) result = graphDb_data_Access.merge_duplicate_nodes(duplicate_nodes_list) + end = time.time() + elapsed_time = end - start + json_obj = {'api_name':'merge_duplicate_nodes','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc)), 'elapsed_api_time':f'{elapsed_time:.2f}'} + logger.log_struct(json_obj, "INFO") return create_api_response('Success',data=result,message="Duplicate entities merged successfully") except Exception as e: job_status = "Failed" diff --git a/backend/src/main.py b/backend/src/main.py index ce8c9812a..d48947811 100644 --- a/backend/src/main.py +++ b/backend/src/main.py @@ -309,6 +309,7 @@ def processing_source(uri, userName, password, database, model, file_name, pages elapsed_get_chunkId_chunkDoc_list = end_get_chunkId_chunkDoc_list - start_get_chunkId_chunkDoc_list logging.info(f'Time taken to create list chunkids with chunk document: {elapsed_get_chunkId_chunkDoc_list:.2f} seconds') uri_latency["create_list_chunk_and_document"] = f'{elapsed_get_chunkId_chunkDoc_list:.2f}' + uri_latency["total_chunks"] = total_chunks start_status_document_node = time.time() result = graphDb_data_Access.get_current_status_document_node(file_name) @@ -369,8 +370,8 @@ def processing_source(uri, userName, password, database, model, file_name, pages processing_chunks_end_time = time.time() processing_chunks_elapsed_end_time = processing_chunks_end_time - processing_chunks_start_time logging.info(f"Time taken {update_graph_chunk_processed} chunks processed upto {select_chunks_upto} completed in {processing_chunks_elapsed_end_time:.2f} seconds for file name {file_name}") - uri_latency[f'processed_combine_chunk_{i}'] = f'{processing_chunks_elapsed_end_time:.2f}' - uri_latency[f'processed_chunk_detail_{i}'] = latency_processed_chunk + uri_latency[f'processed_combine_chunk_{i}-{select_chunks_upto}'] = f'{processing_chunks_elapsed_end_time:.2f}' + uri_latency[f'processed_chunk_detail_{i}-{select_chunks_upto}'] = latency_processed_chunk end_time = datetime.now() processed_time = end_time - start_time @@ -418,6 +419,7 @@ def processing_source(uri, userName, password, database, model, file_name, pages processing_source_func = time.time() - processing_source_start_time logging.info(f"Time taken to processing source function completed in {processing_source_func:.2f} seconds for file name {file_name}") uri_latency["Processed_source"] = f'{processing_source_func:.2f}' + uri_latency["Per_entity_latency"] = f'{int(processing_source_func)/node_count:.2f}/s' uri_latency["fileName"] = file_name uri_latency["nodeCount"] = node_count uri_latency["relationshipCount"] = rel_count From 393c53c53f9a88e1e1a13b12bd1b5320bd5cb876 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Tue, 1 Oct 2024 05:46:24 +0000 Subject: [PATCH 148/292] Added the post processing Alert showcasing the ongoing post processing jobs --- frontend/src/components/Content.tsx | 7 ++-- .../PostProcessingToast.tsx | 18 ++++++++ .../SelectedJobList.tsx | 42 +++++++++++++++++++ .../Popups/RetryConfirmation/Index.tsx | 2 +- frontend/src/utils/toasts.ts | 3 +- 5 files changed, 67 insertions(+), 5 deletions(-) create mode 100644 frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/PostProcessingToast.tsx create mode 100644 frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 53bf47058..f74ca7020 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -34,6 +34,7 @@ import RetryConfirmationDialog from './Popups/RetryConfirmation/Index'; import retry from '../services/retry'; import { showErrorToast, showNormalToast, showSuccessToast } from '../utils/toasts'; import { useMessageContext } from '../context/UserMessages'; +import PostProcessingToast from './Popups/GraphEnhancementDialog/PostProcessingCheckList/PostProcessingToast'; const ConnectionModal = lazy(() => import('./Popups/ConnectionModal/ConnectionModal')); const ConfirmationDialog = lazy(() => import('./Popups/LargeFilePopUp/ConfirmationDialog')); @@ -159,12 +160,12 @@ const Content: React.FC = ({ } if (processedCount === 1 && queue.isEmpty()) { (async () => { - showNormalToast('Some Q&A functionality will only be available afterwards.'); + showNormalToast(); await postProcessing(userCredentials as UserCredentials, postProcessingTasks); showSuccessToast('All Q&A functionality is available now.'); })(); } - }, [processedCount, userCredentials, queue, isReadOnlyUser]); + }, [processedCount, userCredentials, queue, isReadOnlyUser, isGdsActive]); useEffect(() => { if (afterFirstRender) { @@ -393,7 +394,7 @@ const Content: React.FC = ({ const addFilesToQueue = async (remainingFiles: CustomFile[]) => { if (!remainingFiles.length) { - showNormalToast('Some Q&A functionality will only be available afterwards.'); + showNormalToast(); await postProcessing(userCredentials as UserCredentials, postProcessingTasks); showSuccessToast('All Q&A functionality is available now.'); } diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/PostProcessingToast.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/PostProcessingToast.tsx new file mode 100644 index 000000000..efb9ca8a2 --- /dev/null +++ b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/PostProcessingToast.tsx @@ -0,0 +1,18 @@ +import { Flex, Typography } from '@neo4j-ndl/react'; +import SelectedJobList from './SelectedJobList'; + +export default function PostProcessingToast({ + postProcessingTasks, + isGdsActive, +}: { + postProcessingTasks: string[]; + isGdsActive: boolean; +}) { + return ( + + Some Q&A functionality will only be available afterwards + Ongoing Post Processing Jobs + + + ); +} diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx new file mode 100644 index 000000000..1cb3c7310 --- /dev/null +++ b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx @@ -0,0 +1,42 @@ +import { Checkbox, Flex, Typography } from '@neo4j-ndl/react'; +import { capitalize } from '../../../../utils/Utils'; +import { useMemo } from 'react'; + +export default function SelectedJobList({ + postProcessingTasks, + isGdsActive, +}: { + postProcessingTasks: string[]; + isGdsActive: boolean; +}) { + const ongoingPostProcessingTasks = useMemo( + () => + (isGdsActive + ? postProcessingTasks.includes('enable_communities') + ? postProcessingTasks + : postProcessingTasks.filter((s) => s != 'enable_communities') + : postProcessingTasks.filter((s) => s != 'enable_communities')), + [isGdsActive, postProcessingTasks] + ); + return ( + + {ongoingPostProcessingTasks.map((task) => { + return ( + + {task + .split('_') + .map((s) => capitalize(s)) + .join(' ')} + + } + checked={true} + disabled={true} + aria-label='Selected-postprocessing-jobs' + /> + ); + })} + + ); +} diff --git a/frontend/src/components/Popups/RetryConfirmation/Index.tsx b/frontend/src/components/Popups/RetryConfirmation/Index.tsx index a510352aa..6ebb02e33 100644 --- a/frontend/src/components/Popups/RetryConfirmation/Index.tsx +++ b/frontend/src/components/Popups/RetryConfirmation/Index.tsx @@ -83,4 +83,4 @@ function RetryConfirmationDialog({ ); } -export default memo(RetryConfirmationDialog); \ No newline at end of file +export default memo(RetryConfirmationDialog); diff --git a/frontend/src/utils/toasts.ts b/frontend/src/utils/toasts.ts index 832c33b9a..ebe6ae709 100644 --- a/frontend/src/utils/toasts.ts +++ b/frontend/src/utils/toasts.ts @@ -1,4 +1,5 @@ import { toast } from '@neo4j-ndl/react'; +import { ReactNode } from 'react'; export const showErrorToast = (message: string, shouldAutoClose: boolean = true) => { return toast.danger(message, { @@ -14,7 +15,7 @@ export const showSuccessToast = (message: string) => { }); }; -export const showNormalToast = (message: string) => { +export const showNormalToast = (message: string | ReactNode) => { return toast.neutral(message, { isCloseable: true, shouldAutoClose: true, From 0dec005465baee7e165f9e25a6d530a38d7280e7 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Tue, 1 Oct 2024 11:54:23 +0000 Subject: [PATCH 149/292] fix: readonly user retry option disable --- frontend/src/components/FileTable.tsx | 33 +++++++++++++-------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/frontend/src/components/FileTable.tsx b/frontend/src/components/FileTable.tsx index 8855a746e..4b6d4bb7e 100644 --- a/frontend/src/components/FileTable.tsx +++ b/frontend/src/components/FileTable.tsx @@ -146,22 +146,21 @@ const FileTable = forwardRef((props, ref) => { > {info.getValue()} - {(info.getValue() === 'Completed' || - info.getValue() === 'Failed' || - (info.getValue() === 'Cancelled' && !isReadOnlyUser)) && ( - - onRetry(info?.row?.id as string)} - > - - - - )} + {(info.getValue() === 'Completed' || info.getValue() === 'Failed' || info.getValue() === 'Cancelled') && + !isReadOnlyUser && ( + + onRetry(info?.row?.id as string)} + > + + + + )}
    ); } else if (info.getValue() === 'Processing' && info.row.original.processingProgress === undefined) { @@ -511,7 +510,7 @@ const FileTable = forwardRef((props, ref) => { footer: (info) => info.column.id, }), ], - [filesData.length, statusFilter, filetypeFilter, llmtypeFilter, fileSourceFilter] + [filesData.length, statusFilter, filetypeFilter, llmtypeFilter, fileSourceFilter, isReadOnlyUser] ); const table = useReactTable({ From ac3d88a9d18d6e7e67b483a77392004b9f359297 Mon Sep 17 00:00:00 2001 From: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Date: Thu, 3 Oct 2024 09:30:01 +0000 Subject: [PATCH 150/292] update script to get details of extarcted doc --- backend/test_integrationqa.py | 75 ++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/backend/test_integrationqa.py b/backend/test_integrationqa.py index 832546995..0281c91f8 100644 --- a/backend/test_integrationqa.py +++ b/backend/test_integrationqa.py @@ -7,21 +7,22 @@ from dotenv import load_dotenv from score import * from src.main import * -from src.QA_integration_new import QA_RAG +from src.QA_integration import QA_RAG from langserve import add_routes # Load environment variables if needed load_dotenv() -# Constants -URI = '' -USERNAME = '' -PASSWORD = '' -DATABASE = 'neo4j' +import os +URI = os.getenv('NEO4J_URI') +USERNAME = os.getenv('NEO4J_USERNAME') +PASSWORD = os.getenv('NEO4J_PASSWORD') +DATABASE = os.getenv('NEO4J_DATABASE') + CHUNK_DIR = os.path.join(os.path.dirname(__file__), "chunks") MERGED_DIR = os.path.join(os.path.dirname(__file__), "merged_files") # Initialize database connection -graph = create_graph_database_connection(URI, USERNAME, PASSWORD, DATABASE) +graph = create_graph_database_connection(URI,USERNAME,PASSWORD,DATABASE) def create_source_node_local(graph, model, file_name): """Creates a source node for a local file.""" @@ -36,6 +37,17 @@ def create_source_node_local(graph, model, file_name): graphDB_data_Access.create_source_node(source_node) return source_node +def delete_extracted_files(file_path): + """Delete the extracted files once extraction process is completed""" + try: + if os.path.exists(file_path): + os.remove(file_path) + logging.info(f"Deleted file:{file_path}") + else: + logging.warning(f"File not found for deletion: {file_path}") + except Exception as e: + logging.error(f"Failed to delete file {file_path}. Error: {e}") + def test_graph_from_file_local(model_name): """Test graph creation from a local file.""" file_name = 'About Amazon.pdf' @@ -51,13 +63,16 @@ def test_graph_from_file_local(model_name): logging.info("Local file processing complete") print(local_file_result) - try: - assert local_file_result['status'] == 'Completed' - assert local_file_result['nodeCount'] > 0 - assert local_file_result['relationshipCount'] > 0 - print("Success") - except AssertionError as e: - print("Fail: ", e) +# try: +# assert local_file_result['status'] == 'Completed' +# assert local_file_result['nodeCount'] > 0 +# assert local_file_result['relationshipCount'] > 0 +# print("Success") +# except AssertionError as e: +# print("Fail: ", e) + + # Delete the file after processing + delete_extracted_files(merged_file_path) return local_file_result @@ -182,25 +197,11 @@ def test_populate_graph_schema_from_text(model): print(result_schema) return result_schema -# def compare_graph_results(results): -# """ -# Compare graph results across different models. -# Add custom logic here to compare graph data, nodes, and relationships. -# """ -# # Placeholder logic for comparison -# print("Comparing results...") -# for i in range(len(results) - 1): -# result_a = results[i] -# result_b = results[i + 1] -# if result_a == result_b: -# print(f"Result {i} is identical to result {i+1}") -# else: -# print(f"Result {i} differs from result {i+1}") def run_tests(): final_list = [] error_list = [] - models = ['openai-gpt-3.5','openai-gpt-4o','openai-gpt-4o-mini','gemini-1.0-pro','gemini-1.5-pro','azure_ai_gpt_35','azure_ai_gpt_4o','ollama_llama3','groq_llama3_70b','anthropic_claude_3_5_sonnet','fireworks_v3p1_405b','bedrock_claude_3_5_sonnet'] + models = ['openai-gpt-3.5','openai-gpt-4o','openai-gpt-4o-mini','gemini-1.5-pro','gemini 1.5 Flash','azure_ai_gpt_35','azure_ai_gpt_4o','ollama_llama3','ollama','groq_llama3_70b','anthropic_claude_3_5_sonnet','bedrock_claude_3_5_sonnet','fireworks_llama_v3p2_90b'] for model_name in models: try: @@ -208,7 +209,7 @@ def run_tests(): final_list.append(test_graph_from_wikipedia(model_name)) final_list.append(test_populate_graph_schema_from_text(model_name)) final_list.append(test_graph_website(model_name)) - # final_list.append(test_graph_from_youtube_video(model_name)) + final_list.append(test_graph_from_youtube_video(model_name)) final_list.append(test_chatbot_qna(model_name)) final_list.append(test_chatbot_qna(model_name, mode='vector')) final_list.append(test_chatbot_qna(model_name, mode='graph+vector')) @@ -221,19 +222,19 @@ def run_tests(): # #Compare and log diffrences in graph results # # compare_graph_results(final_list) # Pass the final_list to comapre_graph_results # test_populate_graph_schema_from_text('openai-gpt-4o') - dis_elementid, dis_status = disconected_nodes() - lst_element_id = [dis_elementid] - delt = delete_disconected_nodes(lst_element_id) - dup = get_duplicate_nodes() +# dis_elementid, dis_status = disconected_nodes() +# lst_element_id = [dis_elementid] +# delt = delete_disconected_nodes(lst_element_id) +# dup = get_duplicate_nodes() print(final_list) # schma = test_populate_graph_schema_from_text(model) # Save final results to CSV df = pd.DataFrame(final_list) print(df) df['execution_date'] = dt.today().strftime('%Y-%m-%d') - df['disconnected_nodes']=dis_status - df['get_duplicate_nodes']=dup - df['delete_disconected_nodes']=delt +# df['disconnected_nodes']=dis_status +# df['get_duplicate_nodes']=dup +# df['delete_disconected_nodes']=delt # df['test_populate_graph_schema_from_text'] = schma df.to_csv(f"Integration_TestResult_{dt.now().strftime('%Y%m%d_%H%M%S')}.csv", index=False) From 83351acf6aeac43a7c7f7c6ef2c1e46f8fc78007 Mon Sep 17 00:00:00 2001 From: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Date: Thu, 3 Oct 2024 09:41:08 +0000 Subject: [PATCH 151/292] Issue fixed, Latency count per entity --- backend/score.py | 1 - backend/src/main.py | 5 ++++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/backend/score.py b/backend/score.py index eba6c3a00..8887d6450 100644 --- a/backend/score.py +++ b/backend/score.py @@ -426,7 +426,6 @@ async def upload_large_file_into_chunks(file:UploadFile = File(...), chunkNumber elapsed_time = end - start json_obj = {'api_name':'upload','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc)), 'elapsed_api_time':f'{elapsed_time:.2f}'} logger.log_struct(json_obj, "INFO") - result['elapsed_api_time'] = f'{elapsed_time:.2f}' if int(chunkNumber) == int(totalChunks): return create_api_response('Success',data=result, message='Source Node Created Successfully') else: diff --git a/backend/src/main.py b/backend/src/main.py index d48947811..731ff56e5 100644 --- a/backend/src/main.py +++ b/backend/src/main.py @@ -419,7 +419,10 @@ def processing_source(uri, userName, password, database, model, file_name, pages processing_source_func = time.time() - processing_source_start_time logging.info(f"Time taken to processing source function completed in {processing_source_func:.2f} seconds for file name {file_name}") uri_latency["Processed_source"] = f'{processing_source_func:.2f}' - uri_latency["Per_entity_latency"] = f'{int(processing_source_func)/node_count:.2f}/s' + if node_count == 0: + uri_latency["Per_entity_latency"] = 'N/A' + else: + uri_latency["Per_entity_latency"] = f'{int(processing_source_func)/node_count}/s' uri_latency["fileName"] = file_name uri_latency["nodeCount"] = node_count uri_latency["relationshipCount"] = rel_count From 178dacbd05184e4bd44529fc88a0501167efc76c Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Fri, 4 Oct 2024 14:58:57 +0530 Subject: [PATCH 152/292] Multiple chat modes selection (#780) * added Multi modes selection * multimodes state mangement * fix: state handling of chat details of the default mode * Added the ChatModeSwitch Component * modes switch statemangement * added the chatmodes switch in both view * removed the copied text * Handled the error scenario * fix: speech issue between modes * fix: Handled activespeech speech and othermessage modes switch * used requestanimationframe instead of setTimeOut * removed the commented code --- backend/score.py | 2 +- frontend/src/assets/ChatbotMessages.json | 39 +- .../src/components/ChatBot/ChatModeToggle.tsx | 31 +- .../components/ChatBot/ChatModesSwitch.tsx | 47 ++ frontend/src/components/ChatBot/Chatbot.tsx | 609 ++++++++++-------- .../components/ChatBot/CommonChatActions.tsx | 56 ++ frontend/src/components/Layout/SideNav.tsx | 9 +- frontend/src/context/UsersFiles.tsx | 6 +- frontend/src/hooks/useSpeech.tsx | 17 +- frontend/src/types.ts | 31 +- frontend/src/utils/Constants.ts | 2 +- 11 files changed, 486 insertions(+), 363 deletions(-) create mode 100644 frontend/src/components/ChatBot/ChatModesSwitch.tsx create mode 100644 frontend/src/components/ChatBot/CommonChatActions.tsx diff --git a/backend/score.py b/backend/score.py index 8887d6450..1162e7a80 100644 --- a/backend/score.py +++ b/backend/score.py @@ -323,7 +323,7 @@ async def chat_bot(uri=Form(),model=Form(None),userName=Form(), password=Form(), message="Unable to get chat response" error_message = str(e) logging.exception(f'Exception in chat bot:{error_message}') - return create_api_response(job_status, message=message, error=error_message) + return create_api_response(job_status, message=message, error=error_message,data=mode) finally: gc.collect() diff --git a/frontend/src/assets/ChatbotMessages.json b/frontend/src/assets/ChatbotMessages.json index e245c61e4..c264938b1 100644 --- a/frontend/src/assets/ChatbotMessages.json +++ b/frontend/src/assets/ChatbotMessages.json @@ -1,40 +1,15 @@ { "listMessages": [ - { - "id": 1, - "message": "Hi, I need help with creating a Cypher query for Neo4j.", - "user": "user", - "datetime": "01/01/2024 00:00:00" - }, { "id": 2, - "message": " Welcome to the Neo4j Knowledge Graph Chat. You can ask questions related to documents which have been completely processed.", - "user": "chatbot", - "datetime": "01/01/2024 00:00:00" - }, - { - "id": 3, - "message": "I need to find all employees who work in the IT department.", - "user": "user", - "datetime": "01/01/2024 00:00:00" - }, - { - "id": 4, - "message": "Alright, you can use the following query: `MATCH (e:Employee)-[:WORKS_IN]->(d:Department {name: 'IT'}) RETURN e.name`. This query matches nodes labeled 'Employee' related to the 'IT' department and returns their names.", - "user": "chatbot", - "datetime": "01/01/2024 00:00:00" - }, - { - "id": 5, - "message": "Thanks! And how do I get the total number of such employees?", - "user": "user", - "datetime": "01/01/2024 00:00:00" - }, - { - "id": 6, - "message": "To get the count, use: `MATCH (e:Employee)-[:WORKS_IN]->(d:Department {name: 'IT'}) RETURN count(e)`. This counts all the distinct 'Employee' nodes related to the 'IT' department.", + "modes":{ + "graph+vector+fulltext":{ + "message": " Welcome to the Neo4j Knowledge Graph Chat. You can ask questions related to documents which have been completely processed." + } + }, "user": "chatbot", - "datetime": "01/01/2024 00:00:00" + "datetime": "01/01/2024 00:00:00", + "currentMode":"graph+vector+fulltext" } ] } \ No newline at end of file diff --git a/frontend/src/components/ChatBot/ChatModeToggle.tsx b/frontend/src/components/ChatBot/ChatModeToggle.tsx index df44985be..b6ece4702 100644 --- a/frontend/src/components/ChatBot/ChatModeToggle.tsx +++ b/frontend/src/components/ChatBot/ChatModeToggle.tsx @@ -2,10 +2,11 @@ import { StatusIndicator, Typography } from '@neo4j-ndl/react'; import { useMemo, useEffect } from 'react'; import { useFileContext } from '../../context/UsersFiles'; import CustomMenu from '../UI/Menu'; -import { chatModeLables, chatModes } from '../../utils/Constants'; +import { chatModeLables, chatModes as AvailableModes } from '../../utils/Constants'; import { capitalize } from '@mui/material'; import { capitalizeWithPlus } from '../../utils/Utils'; import { useCredentials } from '../../context/UserCredentials'; + export default function ChatModeToggle({ menuAnchor, closeHandler = () => {}, @@ -19,22 +20,22 @@ export default function ChatModeToggle({ anchorPortal?: boolean; disableBackdrop?: boolean; }) { - const { setchatMode, chatMode, postProcessingTasks, selectedRows } = useFileContext(); + const { setchatModes, chatModes, postProcessingTasks, selectedRows } = useFileContext(); const isCommunityAllowed = postProcessingTasks.includes('enable_communities'); const { isGdsActive } = useCredentials(); useEffect(() => { // If rows are selected, the mode is valid (either vector or graph+vector) if (selectedRows.length > 0) { - if (!(chatMode === chatModeLables.vector || chatMode === chatModeLables.graph_vector)) { - setchatMode(chatModeLables.graph_vector); + if (!(chatModes.includes(chatModeLables.vector) || chatModes.includes(chatModeLables.graph_vector))) { + setchatModes([chatModeLables.graph_vector]); } } - }, [selectedRows.length, chatMode, setchatMode]); + }, [selectedRows.length, chatModes.length]); const memoizedChatModes = useMemo(() => { return isGdsActive && isCommunityAllowed - ? chatModes - : chatModes?.filter( + ? AvailableModes + : AvailableModes?.filter( (m) => !m.mode.includes(chatModeLables.entity_vector) && !m.mode.includes(chatModeLables.global_vector) ); }, [isGdsActive, isCommunityAllowed]); @@ -45,9 +46,11 @@ export default function ChatModeToggle({ ); const handleModeChange = () => { if (isDisabled) { - setchatMode(chatModeLables.graph_vector); + setchatModes([chatModeLables.graph_vector]); + } else if (chatModes.includes(m.mode)) { + setchatModes((prev) => prev.filter((i) => i != m.mode)); } else { - setchatMode(m.mode); + setchatModes((prev) => [...prev, m.mode]); } closeHandler(); }; @@ -66,7 +69,7 @@ export default function ChatModeToggle({ disabledCondition: isDisabled, description: ( - {chatMode === m.mode && ( + {chatModes.includes(m.mode) && ( <> {chatModeLables.selected} @@ -80,13 +83,13 @@ export default function ChatModeToggle({ ), }; }); - }, [chatMode, memoizedChatModes, setchatMode, closeHandler, selectedRows]); + }, [chatModes.length, memoizedChatModes, closeHandler, selectedRows]); useEffect(() => { - if (!selectedRows.length && !chatMode) { - setchatMode(chatModeLables.graph_vector_fulltext); + if (!selectedRows.length && !chatModes.length) { + setchatModes([chatModeLables.graph_vector_fulltext]); } - }, [setchatMode, selectedRows.length, chatMode]); + }, [selectedRows.length, chatModes.length]); return ( void; + currentModeIndex: number; + modescount: number; + currentMode: string; + isFullScreen: boolean; +}) { + const chatmodetoshow = currentMode.includes('+') ? capitalizeWithPlus(currentMode) : capitalize(currentMode); + return ( + + switchToOtherMode(currentModeIndex - 1)} + > + + + + + {chatmodetoshow} + + + switchToOtherMode(currentModeIndex + 1)} + > + + + + ); +} diff --git a/frontend/src/components/ChatBot/Chatbot.tsx b/frontend/src/components/ChatBot/Chatbot.tsx index 550d04c97..2d23ec452 100644 --- a/frontend/src/components/ChatBot/Chatbot.tsx +++ b/frontend/src/components/ChatBot/Chatbot.tsx @@ -1,26 +1,31 @@ -import React, { FC, lazy, Suspense, useEffect, useRef, useState } from 'react'; -import { Widget, Typography, Avatar, TextInput, IconButton, Modal, useCopyToClipboard } from '@neo4j-ndl/react'; +import React, { FC, lazy, Suspense, useCallback, useEffect, useRef, useState } from 'react'; import { - XMarkIconOutline, - ClipboardDocumentIconOutline, - SpeakerWaveIconOutline, - SpeakerXMarkIconOutline, -} from '@neo4j-ndl/react/icons'; + Widget, + Typography, + Avatar, + TextInput, + IconButton, + Modal, + useCopyToClipboard, + Flex, + Box, +} from '@neo4j-ndl/react'; +import { XMarkIconOutline } from '@neo4j-ndl/react/icons'; import ChatBotAvatar from '../../assets/images/chatbot-ai.png'; -import { ChatbotProps, CustomFile, UserCredentials, nodeDetailsProps } from '../../types'; +import { ChatbotProps, CustomFile, Messages, ResponseMode, UserCredentials, nodeDetailsProps } from '../../types'; import { useCredentials } from '../../context/UserCredentials'; import { chatBotAPI } from '../../services/QnaAPI'; import { v4 as uuidv4 } from 'uuid'; import { useFileContext } from '../../context/UsersFiles'; import clsx from 'clsx'; import ReactMarkdown from 'react-markdown'; -import { IconButtonWithToolTip } from '../UI/IconButtonToolTip'; -import { buttonCaptions, chatModeLables, tooltips } from '../../utils/Constants'; +import { buttonCaptions, chatModeLables } from '../../utils/Constants'; import useSpeechSynthesis from '../../hooks/useSpeech'; import ButtonWithToolTip from '../UI/ButtonWithToolTip'; import FallBackDialog from '../UI/FallBackDialog'; -import { capitalizeWithPlus } from '../../utils/Utils'; -import { capitalize } from '@mui/material'; +import { getDateTime } from '../../utils/Utils'; +import ChatModesSwitch from './ChatModesSwitch'; +import CommonActions from './CommonChatActions'; const InfoModal = lazy(() => import('./ChatInfoModal')); const Chatbot: FC = (props) => { @@ -35,7 +40,7 @@ const Chatbot: FC = (props) => { const [inputMessage, setInputMessage] = useState(''); const [loading, setLoading] = useState(isLoading); const { userCredentials } = useCredentials(); - const { model, chatMode, selectedRows, filesData } = useFileContext(); + const { model, chatModes, selectedRows, filesData } = useFileContext(); const messagesEndRef = useRef(null); const [sessionId, setSessionId] = useState(sessionStorage.getItem('session_id') ?? ''); const [showInfoModal, setShowInfoModal] = useState(false); @@ -44,15 +49,14 @@ const Chatbot: FC = (props) => { const [responseTime, setResponseTime] = useState(0); const [tokensUsed, setTokensUsed] = useState(0); const [cypherQuery, setcypherQuery] = useState(''); - const [copyMessageId, setCopyMessageId] = useState(null); const [chatsMode, setChatsMode] = useState(chatModeLables.graph_vector_fulltext); const [graphEntitites, setgraphEntitites] = useState<[]>([]); const [messageError, setmessageError] = useState(''); const [entitiesModal, setEntitiesModal] = useState([]); const [nodeDetailsModal, setNodeDetailsModal] = useState({}); - const [value, copy] = useCopyToClipboard(); - const { speak, cancel } = useSpeechSynthesis({ + const [_, copy] = useCopyToClipboard(); + const { speak, cancel, speaking } = useSpeechSynthesis({ onEnd: () => { setListMessages((msgs) => msgs.map((msg) => ({ ...msg, speaking: false }))); }, @@ -65,6 +69,7 @@ const Chatbot: FC = (props) => { const handleInputChange = (e: React.ChangeEvent) => { setInputMessage(e.target.value); }; + useEffect(() => { if (!sessionStorage.getItem('session_id')) { const id = uuidv4(); @@ -72,160 +77,178 @@ const Chatbot: FC = (props) => { sessionStorage.setItem('session_id', id); } }, []); - const simulateTypingEffect = ( - response: { - reply: string; - sources?: string[]; - model?: string; - total_tokens?: number; - response_time?: number; - speaking?: boolean; - copying?: boolean; - mode?: string; - cypher_query?: string; - graphonly_entities?: []; - error?: string; - entitiysearchonly_entities?: string[]; - nodeDetails?: nodeDetailsProps; - }, - index = 0 - ) => { - if (index < response.reply.length) { - const nextIndex = index + 1; - const currentTypedText = response.reply.substring(0, nextIndex); - if (index === 0) { - const date = new Date(); - const datetime = `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`; - if (response.reply.length <= 1) { - setListMessages((msgs) => [ - ...msgs, - { - id: Date.now(), - user: 'chatbot', - message: currentTypedText, - datetime: datetime, - isTyping: false, - isLoading: true, - sources: response?.sources, - model: response?.model, - total_tokens: response.total_tokens, - response_time: response?.response_time, - speaking: false, - copying: false, - mode: response?.mode, - cypher_query: response?.cypher_query, - graphonly_entities: response?.graphonly_entities, - error: response.error, - entitiysearchonly_entities: response.entitiysearchonly_entities, - nodeDetails: response?.nodeDetails, - }, - ]); - } else { - setListMessages((msgs) => { - const lastmsg = { ...msgs[msgs.length - 1] }; - lastmsg.id = Date.now(); - lastmsg.user = 'chatbot'; - lastmsg.message = currentTypedText; - lastmsg.datetime = datetime; - lastmsg.isTyping = true; - lastmsg.isLoading = false; - lastmsg.sources = response?.sources; - lastmsg.model = response?.model; - lastmsg.total_tokens = response?.total_tokens; - lastmsg.response_time = response?.response_time; - lastmsg.speaking = false; - lastmsg.copying = false; - lastmsg.mode = response?.mode; - lastmsg.cypher_query = response.cypher_query; - lastmsg.graphonly_entities = response.graphonly_entities; - lastmsg.error = response.error; - lastmsg.entities = response.entitiysearchonly_entities; - lastmsg.nodeDetails = response?.nodeDetails; - return msgs.map((msg, index) => { - if (index === msgs.length - 1) { - return lastmsg; + + const simulateTypingEffect = (messageId: number, response: ResponseMode, mode: string, message: string) => { + let index = 0; + let lastTimestamp: number | null = null; + const TYPING_INTERVAL = 20; + const animate = (timestamp: number) => { + if (lastTimestamp === null) { + lastTimestamp = timestamp; + } + const elapsed = timestamp - lastTimestamp; + if (elapsed >= TYPING_INTERVAL) { + if (index < message.length) { + const nextIndex = index + 1; + const currentTypedText = message.substring(0, nextIndex); + setListMessages((msgs) => + msgs.map((msg) => { + if (msg.id === messageId) { + return { + ...msg, + modes: { + ...msg.modes, + [mode]: { + ...response, + message: currentTypedText, + }, + }, + isTyping: true, + speaking: false, + copying: false, + }; } return msg; - }); - }); + }) + ); + index = nextIndex; + lastTimestamp = timestamp; + } else { + setListMessages((msgs) => msgs.map((msg) => (msg.id === messageId ? { ...msg, isTyping: false } : msg))); + return; } - } else { - setListMessages((msgs) => msgs.map((msg) => (msg.isTyping ? { ...msg, message: currentTypedText } : msg))); } - setTimeout(() => simulateTypingEffect(response, nextIndex), 20); - } else { - setListMessages((msgs) => msgs.map((msg) => (msg.isTyping ? { ...msg, isTyping: false } : msg))); - } + requestAnimationFrame(animate); + }; + requestAnimationFrame(animate); }; - let date = new Date(); const handleSubmit = async (e: { preventDefault: () => void }) => { e.preventDefault(); if (!inputMessage.trim()) { return; } - let chatbotReply; - let chatSources; - let chatModel; - let chatnodedetails; - let chatTimeTaken; - let chatTokensUsed; - let chatingMode; - let cypher_query; - let graphonly_entities; - let error; - let entitiysearchonly_entities; - let chatEntities; - const datetime = `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`; - const userMessage = { id: Date.now(), user: 'user', message: inputMessage, datetime: datetime, mode: chatMode }; + const datetime = getDateTime(); + const userMessage: Messages = { + id: Date.now(), + user: 'user', + datetime: datetime, + currentMode: chatModes[0], + modes: {}, + }; + userMessage.modes[chatModes[0]] = { message: inputMessage }; setListMessages([...listMessages, userMessage]); + const chatbotMessageId = Date.now() + 1; + const chatbotMessage: Messages = { + id: chatbotMessageId, + user: 'chatbot', + datetime: new Date().toLocaleString(), + isTyping: true, + isLoading: true, + modes: {}, + currentMode: chatModes[0], + }; + setListMessages((prev) => [...prev, chatbotMessage]); try { + const apiCalls = chatModes.map((mode) => + chatBotAPI( + userCredentials as UserCredentials, + inputMessage, + sessionId, + model, + mode, + selectedFileNames?.map((f) => f.name) + ) + ); setInputMessage(''); - simulateTypingEffect({ reply: ' ' }); - const chatbotAPI = await chatBotAPI( - userCredentials as UserCredentials, - inputMessage, - sessionId, - model, - chatMode, - selectedFileNames?.map((f) => f.name) + const results = await Promise.allSettled(apiCalls); + results.forEach((result, index) => { + const mode = chatModes[index]; + if (result.status === 'fulfilled') { + // @ts-ignore + if (result.value.response.data.status === 'Success') { + const response = result.value.response.data.data; + const responseMode: ResponseMode = { + message: response.message, + sources: response.info.sources, + model: response.info.model, + total_tokens: response.info.total_tokens, + response_time: response.info.response_time, + cypher_query: response.info.cypher_query, + graphonly_entities: response.info.context, + entities: response.info.entities, + nodeDetails: response.info.nodedetails, + error: response.info.error, + }; + if (index === 0) { + simulateTypingEffect(chatbotMessageId, responseMode, mode, responseMode.message); + } else { + setListMessages((prev) => + prev.map((msg) => + (msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg) + ) + ); + } + } else { + const response = result.value.response.data; + const responseMode: ResponseMode = { + message: response.message, + error: response.error, + }; + if (index === 0) { + simulateTypingEffect(chatbotMessageId, responseMode, response.data, responseMode.message); + } else { + setListMessages((prev) => + prev.map((msg) => + (msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg) + ) + ); + } + } + } else { + console.error(`API call failed for mode ${mode}:`, result.reason); + setListMessages((prev) => + prev.map((msg) => + (msg.id === chatbotMessageId + ? { + ...msg, + modes: { + ...msg.modes, + [mode]: { message: 'Failed to fetch response for this mode.', error: result.reason }, + }, + } + : msg) + ) + ); + } + }); + setListMessages((prev) => + prev.map((msg) => (msg.id === chatbotMessageId ? { ...msg, isLoading: false, isTyping: false } : msg)) ); - const chatresponse = chatbotAPI?.response; - chatbotReply = chatresponse?.data?.data?.message; - chatSources = chatresponse?.data?.data?.info.sources; - chatModel = chatresponse?.data?.data?.info.model; - chatnodedetails = chatresponse?.data?.data?.info.nodedetails; - chatTokensUsed = chatresponse?.data?.data?.info.total_tokens; - chatTimeTaken = chatresponse?.data?.data?.info.response_time; - chatingMode = chatresponse?.data?.data?.info?.mode; - cypher_query = chatresponse?.data?.data?.info?.cypher_query ?? ''; - graphonly_entities = chatresponse?.data.data.info.context ?? []; - entitiysearchonly_entities = chatresponse?.data.data.info.entities; - error = chatresponse.data.data.info.error ?? ''; - chatEntities = chatresponse.data.data.info.entities; - const finalbotReply = { - reply: chatbotReply, - sources: chatSources, - model: chatModel, - total_tokens: chatTokensUsed, - response_time: chatTimeTaken, - speaking: false, - copying: false, - mode: chatingMode, - cypher_query, - graphonly_entities, - error, - entitiysearchonly_entities, - chatEntities, - nodeDetails: chatnodedetails, - }; - simulateTypingEffect(finalbotReply); } catch (error) { - chatbotReply = "Oops! It seems we couldn't retrieve the answer. Please try again later"; - setInputMessage(''); - simulateTypingEffect({ reply: chatbotReply }); + console.error('Error in handling chat:', error); + if (error instanceof Error) { + setListMessages((prev) => + prev.map((msg) => + (msg.id === chatbotMessageId + ? { + ...msg, + isLoading: false, + isTyping: false, + modes: { + [chatModes[0]]: { + message: 'An error occurred while processing your request.', + error: error.message, + }, + }, + } + : msg) + ) + ); + } } }; + const scrollToBottom = () => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); }; @@ -254,9 +277,7 @@ const Chatbot: FC = (props) => { return msg; }) ); - setCopyMessageId(id); setTimeout(() => { - setCopyMessageId(null); setListMessages((msgs) => msgs.map((msg) => { if (msg.id === id) { @@ -273,152 +294,172 @@ const Chatbot: FC = (props) => { setListMessages((msgs) => msgs.map((msg) => (msg.id === id ? { ...msg, speaking: false } : msg))); }; - const handleSpeak = (chatMessage: any, id: number) => { - speak({ text: chatMessage }); + const handleSpeak = (chatMessage: string, id: number) => { + speak({ text: chatMessage }, typeof window !== 'undefined' && window.speechSynthesis != undefined); setListMessages((msgs) => { const messageWithSpeaking = msgs.find((msg) => msg.speaking); return msgs.map((msg) => (msg.id === id && !messageWithSpeaking ? { ...msg, speaking: true } : msg)); }); }; + const handleSwitchMode = (messageId: number, newMode: string) => { + const activespeechId = listMessages.find((msg) => msg.speaking)?.id; + if (speaking && messageId === activespeechId) { + cancel(); + setListMessages((prev) => + prev.map((msg) => (msg.id === messageId ? { ...msg, currentMode: newMode, speaking: false } : msg)) + ); + } else { + setListMessages((prev) => prev.map((msg) => (msg.id === messageId ? { ...msg, currentMode: newMode } : msg))); + } + }; + + const detailsHandler = useCallback((chat: Messages) => { + const currentMode = chat.modes[chat.currentMode]; + setModelModal(currentMode.model ?? ''); + setSourcesModal(currentMode.sources ?? []); + setResponseTime(currentMode.response_time ?? 0); + setTokensUsed(currentMode.total_tokens ?? 0); + setcypherQuery(currentMode.cypher_query ?? ''); + setShowInfoModal(true); + setChatsMode(chat.currentMode ?? ''); + setgraphEntitites(currentMode.graphonly_entities ?? []); + setEntitiesModal(currentMode.entities ?? []); + setmessageError(currentMode.error ?? ''); + setNodeDetailsModal(currentMode.nodeDetails ?? {}); + }, []); + + const speechHandler = useCallback((chat: Messages) => { + if (chat.speaking) { + handleCancel(chat.id); + } else { + handleSpeak(chat.modes[chat.currentMode]?.message, chat.id); + } + }, []); return (
    - {listMessages.map((chat, index) => ( -
    -
    - {chat.user === 'chatbot' ? ( - - ) : ( - - )} -
    - - Chat Mode: {chat.mode.includes('+') ? capitalizeWithPlus(chat.mode) : capitalize(chat.mode)} - - ) : ( - '' - ) - } + {listMessages.map((chat, index) => { + const messagechatModes = Object.keys(chat.modes); + return ( +
    -
    + {chat.user === 'chatbot' ? ( + + ) : ( + + )} +
    + - {chat.message} -
    -
    -
    - - {chat.datetime} - +
    + {chat.modes[chat.currentMode]?.message || ''}
    - {chat.user === 'chatbot' && chat.id !== 2 && !chat.isLoading && !chat.isTyping && ( -
    - { - setModelModal(chat.model ?? ''); - setSourcesModal(chat.sources ?? []); - setResponseTime(chat.response_time ?? 0); - setTokensUsed(chat.total_tokens ?? 0); - setcypherQuery(chat.cypher_query ?? ''); - setShowInfoModal(true); - setChatsMode(chat.mode ?? ''); - setgraphEntitites(chat.graphonly_entities ?? []); - setEntitiesModal(chat.entities ?? []); - setmessageError(chat.error ?? ''); - setNodeDetailsModal(chat.nodeDetails ?? {}); - }} - > - {' '} - {buttonCaptions.details} - - handleCopy(chat.message, chat.id)} - disabled={chat.isTyping || chat.isLoading} - > - - - {copyMessageId === chat.id && ( - <> - Copied! - {value} - - )} - { - if (chat.speaking) { - handleCancel(chat.id); - } else { - handleSpeak(chat.message, chat.id); - } - }} - text={chat.speaking ? tooltips.stopSpeaking : tooltips.textTospeech} - disabled={listMessages.some((msg) => msg.speaking && msg.id !== chat.id)} - label={chat.speaking ? 'stop speaking' : 'text to speech'} - > - {chat.speaking ? ( - - ) : ( - - )} - +
    +
    + + {chat.datetime} +
    - )} -
    - -
    - ))} + {chat.user === 'chatbot' && + chat.id !== 2 && + !chat.isLoading && + !chat.isTyping && + (!isFullScreen ? ( + 1 ? 'space-between' : 'unset'} + alignItems='center' + > + + {messagechatModes.length > 1 && ( + { + const modes = Object.keys(chat.modes); + const modeswtich = modes[index]; + handleSwitchMode(chat.id, modeswtich); + }} + isFullScreen={false} + currentModeIndex={messagechatModes.indexOf(chat.currentMode)} + modescount={messagechatModes.length} + /> + )} + + ) : ( + + + + + + {messagechatModes.length > 1 && ( + { + const modes = Object.keys(chat.modes); + const modeswtich = modes[index]; + handleSwitchMode(chat.id, modeswtich); + }} + isFullScreen={isFullScreen} + currentModeIndex={messagechatModes.indexOf(chat.currentMode)} + modescount={messagechatModes.length} + /> + )} + + + ))} +
    + +
    + ); + })}
    diff --git a/frontend/src/components/ChatBot/CommonChatActions.tsx b/frontend/src/components/ChatBot/CommonChatActions.tsx new file mode 100644 index 000000000..07f04bc8f --- /dev/null +++ b/frontend/src/components/ChatBot/CommonChatActions.tsx @@ -0,0 +1,56 @@ +import { ClipboardDocumentIconOutline, SpeakerWaveIconOutline, SpeakerXMarkIconOutline } from '@neo4j-ndl/react/icons'; +import { Messages } from '../../types'; +import ButtonWithToolTip from '../UI/ButtonWithToolTip'; +import { IconButtonWithToolTip } from '../UI/IconButtonToolTip'; +import { buttonCaptions, tooltips } from '../../utils/Constants'; + +export default function CommonActions({ + chat, + detailsHandler, + speechHandler, + copyHandler, + listMessages, +}: { + chat: Messages; + detailsHandler: (chat: Messages) => void; + speechHandler: (chat: Messages) => void; + copyHandler: (message: string, id: number) => void; + listMessages: Messages[]; +}) { + return ( + <> + detailsHandler(chat)} + > + {buttonCaptions.details} + + copyHandler(chat.modes[chat.currentMode]?.message, chat.id)} + disabled={chat.isTyping || chat.isLoading} + > + + + speechHandler(chat)} + text={chat.speaking ? tooltips.stopSpeaking : tooltips.textTospeech} + disabled={listMessages.some((msg) => msg.speaking && msg.id !== chat.id)} + label={chat.speaking ? 'stop speaking' : 'text to speech'} + > + {chat.speaking ? : } + + + ); +} diff --git a/frontend/src/components/Layout/SideNav.tsx b/frontend/src/components/Layout/SideNav.tsx index e07979405..2472d6e76 100644 --- a/frontend/src/components/Layout/SideNav.tsx +++ b/frontend/src/components/Layout/SideNav.tsx @@ -54,9 +54,14 @@ const SideNav: React.FC = ({ { datetime: `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`, id: 2, - message: - ' Welcome to the Neo4j Knowledge Graph Chat. You can ask questions related to documents which have been completely processed.', + modes: { + 'graph+vector+fulltext': { + message: + ' Welcome to the Neo4j Knowledge Graph Chat. You can ask questions related to documents which have been completely processed.', + }, + }, user: 'chatbot', + currentMode: 'graph+vector+fulltext', }, ]); } diff --git a/frontend/src/context/UsersFiles.tsx b/frontend/src/context/UsersFiles.tsx index 04a435f07..14f5a0245 100644 --- a/frontend/src/context/UsersFiles.tsx +++ b/frontend/src/context/UsersFiles.tsx @@ -29,7 +29,7 @@ const FileContextProvider: FC = ({ children }) => { const [selectedSchemas, setSelectedSchemas] = useState([]); const [rowSelection, setRowSelection] = useState>({}); const [selectedRows, setSelectedRows] = useState([]); - const [chatMode, setchatMode] = useState(chatModeLables.graph_vector_fulltext); + const [chatModes, setchatModes] = useState([chatModeLables.graph_vector_fulltext]); const [isSchema, setIsSchema] = useState(false); const [showTextFromSchemaDialog, setShowTextFromSchemaDialog] = useState({ triggeredFrom: '', @@ -78,8 +78,8 @@ const FileContextProvider: FC = ({ children }) => { setSelectedRows, selectedSchemas, setSelectedSchemas, - chatMode, - setchatMode, + chatModes, + setchatModes, isSchema, setIsSchema, setShowTextFromSchemaDialog, diff --git a/frontend/src/hooks/useSpeech.tsx b/frontend/src/hooks/useSpeech.tsx index d8173f6dd..54c7967f4 100644 --- a/frontend/src/hooks/useSpeech.tsx +++ b/frontend/src/hooks/useSpeech.tsx @@ -1,22 +1,17 @@ -import { useEffect, useState } from 'react'; +import { useState } from 'react'; import { SpeechSynthesisProps, SpeechArgs } from '../types'; const useSpeechSynthesis = (props: SpeechSynthesisProps = {}) => { const { onEnd = () => {} } = props; const [speaking, setSpeaking] = useState(false); - const [supported, setSupported] = useState(false); const handleEnd = () => { setSpeaking(false); onEnd(); }; - useEffect(() => { - if (typeof window !== 'undefined' && window.speechSynthesis) { - setSupported(true); - } - }, []); - const speak = (args: SpeechArgs = {}) => { + + const speak = (args: SpeechArgs = {}, isSupported: boolean) => { const { text = '', rate = 1, pitch = 1, volume = 1 } = args; - if (!supported) { + if (!isSupported) { return; } setSpeaking(true); @@ -29,14 +24,10 @@ const useSpeechSynthesis = (props: SpeechSynthesisProps = {}) => { window.speechSynthesis.speak(utterance); }; const cancel = () => { - if (!supported) { - return; - } setSpeaking(false); window.speechSynthesis.cancel(); }; return { - supported, speak, speaking, cancel, diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 5dc09f418..eb0d6c090 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -206,26 +206,31 @@ export interface ChunkDetail { id: string; score: number; } -export interface Messages { - id: number; +export type ResponseMode = { message: string; - user: string; - datetime: string; - isTyping?: boolean; sources?: string[]; model?: string; - isLoading?: boolean; + total_tokens?: number; response_time?: number; + cypher_query?: string; nodeDetails?: nodeDetailsProps; chunk_ids?: string[]; - total_tokens?: number; - speaking?: boolean; - copying?: boolean; - mode?: string; - cypher_query?: string; graphonly_entities?: []; error?: string; entities?: string[]; +}; +export interface Messages { + id: number; + user: string; + datetime: string; + isTyping?: boolean; + isLoading?: boolean; + speaking?: boolean; + copying?: boolean; + modes: { + [key: string]: ResponseMode; + }; + currentMode: string; } export type ChatbotProps = { @@ -723,8 +728,8 @@ export interface FileContextType { setSelectedRows: React.Dispatch>; selectedSchemas: readonly OptionType[]; setSelectedSchemas: Dispatch>; - chatMode: string; - setchatMode: Dispatch>; + chatModes: string[]; + setchatModes: Dispatch>; isSchema: boolean; setIsSchema: React.Dispatch>; showTextFromSchemaDialog: showTextFromSchemaDialogType; diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index a9a41c0a2..f740531d0 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -311,5 +311,5 @@ export const connectionLabels = { redStroke: 'red', }; export const getDefaultMessage = () => { - return [{ ...chatbotmessages.listMessages[1], datetime: getDateTime() }]; + return [{ ...chatbotmessages.listMessages[0], datetime: getDateTime() }]; }; From 1a33f0d30b260add3868359cf98c31d5714b5702 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Mon, 7 Oct 2024 05:51:36 +0000 Subject: [PATCH 153/292] Fix: ChatModes DeSelection on FIle Selection --- frontend/src/components/ChatBot/ChatModeToggle.tsx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/frontend/src/components/ChatBot/ChatModeToggle.tsx b/frontend/src/components/ChatBot/ChatModeToggle.tsx index b6ece4702..127942c57 100644 --- a/frontend/src/components/ChatBot/ChatModeToggle.tsx +++ b/frontend/src/components/ChatBot/ChatModeToggle.tsx @@ -27,6 +27,17 @@ export default function ChatModeToggle({ useEffect(() => { // If rows are selected, the mode is valid (either vector or graph+vector) if (selectedRows.length > 0) { + if ( + chatModes.includes(chatModeLables.graph) || + chatModes.includes(chatModeLables.fulltext) || + chatModes.includes(chatModeLables.graph_vector_fulltext) + ) { + setchatModes((prev) => + prev.filter( + (m) => ![chatModeLables.graph, chatModeLables.fulltext, chatModeLables.graph_vector_fulltext].includes(m) + ) + ); + } if (!(chatModes.includes(chatModeLables.vector) || chatModes.includes(chatModeLables.graph_vector))) { setchatModes([chatModeLables.graph_vector]); } From e5760553ecfffef3bd6fe0bd40f9e8d6f566f770 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Mon, 7 Oct 2024 07:15:19 +0000 Subject: [PATCH 154/292] Fix: Order of the chatmodes accordoing to selected chatmodes --- frontend/src/components/ChatBot/Chatbot.tsx | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/ChatBot/Chatbot.tsx b/frontend/src/components/ChatBot/Chatbot.tsx index 2d23ec452..e075777db 100644 --- a/frontend/src/components/ChatBot/Chatbot.tsx +++ b/frontend/src/components/ChatBot/Chatbot.tsx @@ -114,7 +114,16 @@ const Chatbot: FC = (props) => { index = nextIndex; lastTimestamp = timestamp; } else { - setListMessages((msgs) => msgs.map((msg) => (msg.id === messageId ? { ...msg, isTyping: false } : msg))); + setListMessages((msgs) => { + const activeMessage = msgs.find((message) => message.id === messageId); + let sortedModes: Record; + if (activeMessage) { + sortedModes = Object.fromEntries( + chatModes.filter((m) => m in activeMessage.modes).map((key) => [key, activeMessage?.modes[key]]) + ); + } + return msgs.map((msg) => (msg.id === messageId ? { ...msg, isTyping: false, modes: sortedModes } : msg)); + }); return; } } @@ -164,6 +173,7 @@ const Chatbot: FC = (props) => { const results = await Promise.allSettled(apiCalls); results.forEach((result, index) => { const mode = chatModes[index]; + console.log({ mode }); if (result.status === 'fulfilled') { // @ts-ignore if (result.value.response.data.status === 'Success') { @@ -222,9 +232,10 @@ const Chatbot: FC = (props) => { ); } }); - setListMessages((prev) => - prev.map((msg) => (msg.id === chatbotMessageId ? { ...msg, isLoading: false, isTyping: false } : msg)) - ); + + setListMessages((prev) => { + return prev.map((msg) => (msg.id === chatbotMessageId ? { ...msg, isLoading: false, isTyping: false } : msg)); + }); } catch (error) { console.error('Error in handling chat:', error); if (error instanceof Error) { From d1a56cab538d30bffc1482e10e11788dd257ca39 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Wed, 9 Oct 2024 11:37:00 +0530 Subject: [PATCH 155/292] Community optimization (#790) * modified leidens parameters * updated disconnected nodes query * excluded communities from dedup * added index creation * modified de dup query * added delete query for communities --- backend/score.py | 4 +- backend/src/communities.py | 107 ++++++++++++++++++++++++++---- backend/src/graphDB_dataAccess.py | 60 ++++++++++++----- backend/src/post_processing.py | 76 ++++++++++++++++++--- backend/src/shared/constants.py | 8 +-- 5 files changed, 211 insertions(+), 44 deletions(-) diff --git a/backend/score.py b/backend/score.py index 1162e7a80..7bc62d186 100644 --- a/backend/score.py +++ b/backend/score.py @@ -14,7 +14,7 @@ from src.graphDB_dataAccess import graphDBdataAccess from src.graph_query import get_graph_results from src.chunkid_entities import get_entities_from_chunkids -from src.post_processing import create_fulltext_indexes, create_entity_embedding +from src.post_processing import create_vector_fulltext_indexes, create_entity_embedding from sse_starlette.sse import EventSourceResponse from src.communities import create_communities import json @@ -270,7 +270,7 @@ async def post_processing(uri=Form(), userName=Form(), password=Form(), database logging.info(f'Updated KNN Graph') if "enable_hybrid_search_and_fulltext_search_in_bloom" in tasks: - await asyncio.to_thread(create_fulltext_indexes, uri=uri, username=userName, password=password, database=database) + await asyncio.to_thread(create_vector_fulltext_indexes, uri=uri, username=userName, password=password, database=database) json_obj = {'api_name': 'post_processing/enable_hybrid_search_and_fulltext_search_in_bloom', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} logging.info(f'Full Text index created') diff --git a/backend/src/communities.py b/backend/src/communities.py index 7086a4786..1b19c689b 100644 --- a/backend/src/communities.py +++ b/backend/src/communities.py @@ -12,6 +12,8 @@ NODE_PROJECTION = "!Chunk&!Document&!__Community__" NODE_PROJECTION_ENTITY = "__Entity__" MAX_WORKERS = 10 +MAX_COMMUNITY_LEVELS = 3 +MIN_COMMUNITY_SIZE = 1 CREATE_COMMUNITY_GRAPH_PROJECTION = """ @@ -143,7 +145,8 @@ ENTITY_VECTOR_INDEX_NAME = "entity_vector" ENTITY_VECTOR_EMBEDDING_DIMENSION = 384 -CREATE_ENTITY_VECTOR_INDEX = """ +DROP_ENTITY_VECTOR_INDEX_QUERY = f"DROP INDEX {ENTITY_VECTOR_INDEX_NAME} IF EXISTS;" +CREATE_ENTITY_VECTOR_INDEX_QUERY = """ CREATE VECTOR INDEX {index_name} IF NOT EXISTS FOR (e:__Entity__) ON e.embedding OPTIONS {{ indexConfig: {{ @@ -151,7 +154,26 @@ `vector.similarity_function`: 'cosine' }} }} -""" +""" + +COMMUNITY_VECTOR_INDEX_NAME = "community_vector" +COMMUNITY_VECTOR_EMBEDDING_DIMENSION = 384 + +DROP_COMMUNITY_VECTOR_INDEX_QUERY = f"DROP INDEX {COMMUNITY_VECTOR_INDEX_NAME} IF EXISTS;" +CREATE_COMMUNITY_VECTOR_INDEX_QUERY = """ +CREATE VECTOR INDEX {index_name} IF NOT EXISTS FOR (c:__Community__) ON c.embedding +OPTIONS {{ + indexConfig: {{ + `vector.dimensions`: {embedding_dimension}, + `vector.similarity_function`: 'cosine' + }} +}} +""" + +COMMUNITY_FULLTEXT_INDEX_NAME = "community_keyword" +COMMUNITY_FULLTEXT_INDEX_DROP_QUERY = f"DROP INDEX {COMMUNITY_FULLTEXT_INDEX_NAME} IF EXISTS;" +COMMUNITY_INDEX_FULL_TEXT_QUERY = f"CREATE FULLTEXT INDEX {COMMUNITY_FULLTEXT_INDEX_NAME} FOR (n:`__Community__`) ON EACH [n.summary]" + def get_gds_driver(uri, username, password, database): @@ -194,7 +216,9 @@ def write_communities(gds, graph_project, project_name=COMMUNITY_PROJECTION_NAME graph_project, writeProperty=project_name, includeIntermediateCommunities=True, - relationshipWeightProperty="weight" + relationshipWeightProperty="weight", + maxLevels=MAX_COMMUNITY_LEVELS, + minCommunitySize=MIN_COMMUNITY_SIZE, ) logging.info("Communities written successfully.") return True @@ -328,18 +352,69 @@ def create_community_embeddings(gds): except Exception as e: logging.error(f"An error occurred during the community embedding process: {e}") -def create_entity_vector_index(gds, embedding_dimension=ENTITY_VECTOR_EMBEDDING_DIMENSION): - query = CREATE_ENTITY_VECTOR_INDEX.format( - index_name=ENTITY_VECTOR_INDEX_NAME, - embedding_dimension=embedding_dimension - ) + +def create_vector_index(gds, index_type,embedding_dimension=None): + drop_query = "" + query = "" + + if index_type == ENTITY_VECTOR_INDEX_NAME: + drop_query = DROP_ENTITY_VECTOR_INDEX_QUERY + query = CREATE_ENTITY_VECTOR_INDEX_QUERY.format( + index_name=ENTITY_VECTOR_INDEX_NAME, + embedding_dimension=embedding_dimension if embedding_dimension else ENTITY_VECTOR_EMBEDDING_DIMENSION + ) + elif index_type == COMMUNITY_VECTOR_INDEX_NAME: + drop_query = DROP_COMMUNITY_VECTOR_INDEX_QUERY + query = CREATE_COMMUNITY_VECTOR_INDEX_QUERY.format( + index_name=COMMUNITY_VECTOR_INDEX_NAME, + embedding_dimension=embedding_dimension if embedding_dimension else COMMUNITY_VECTOR_EMBEDDING_DIMENSION + ) + else: + logging.error(f"Invalid index type provided: {index_type}") + return + try: - logging.info(f"Running Cypher query to create entity vector index: {query}") + logging.info("Starting the process to create vector index.") + + logging.info(f"Executing drop query: {drop_query}") + gds.run_cypher(drop_query) + + logging.info(f"Executing create query: {query}") gds.run_cypher(query) - logging.info("Entity vector index created successfully.") + + logging.info(f"Vector index '{index_type}' created successfully.") + except Exception as e: - logging.error(f"Error occurred while creating entity vector index: {e}", exc_info=True) - + logging.error("An error occurred while creating the vector index.", exc_info=True) + logging.error(f"Error details: {str(e)}") + + +def create_fulltext_index(gds, index_type): + drop_query = "" + query = "" + + if index_type == COMMUNITY_FULLTEXT_INDEX_NAME: + drop_query = COMMUNITY_FULLTEXT_INDEX_DROP_QUERY + query = COMMUNITY_INDEX_FULL_TEXT_QUERY + else: + logging.error(f"Invalid index type provided: {index_type}") + return + + try: + logging.info("Starting the process to create full-text index.") + + logging.info(f"Executing drop query: {drop_query}") + gds.run_cypher(drop_query) + + logging.info(f"Executing create query: {query}") + gds.run_cypher(query) + + logging.info(f"Full-text index '{index_type}' created successfully.") + + except Exception as e: + logging.error("An error occurred while creating the full-text index.", exc_info=True) + logging.error(f"Error details: {str(e)}") + def create_community_properties(gds, model): commands = [ (CREATE_COMMUNITY_CONSTRAINT, "created community constraint to the graph."), @@ -360,9 +435,15 @@ def create_community_properties(gds, model): embedding_dimension = create_community_embeddings(gds) logging.info("Successfully created community embeddings.") - create_entity_vector_index(gds,embedding_dimension=embedding_dimension) + create_vector_index(gds=gds,index_type=ENTITY_VECTOR_INDEX_NAME,embedding_dimension=embedding_dimension) logging.info("Successfully created Entity Vector Index.") + create_vector_index(gds=gds,index_type=COMMUNITY_VECTOR_INDEX_NAME,embedding_dimension=embedding_dimension) + logging.info("Successfully created community Vector Index.") + + create_fulltext_index(gds=gds,index_type=COMMUNITY_FULLTEXT_INDEX_NAME) + logging.info("Successfully created community fulltext Index.") + except Exception as e: logging.error(f"Error during community properties creation: {e}") raise diff --git a/backend/src/graphDB_dataAccess.py b/backend/src/graphDB_dataAccess.py index c2e2f6424..e3b923f37 100644 --- a/backend/src/graphDB_dataAccess.py +++ b/backend/src/graphDB_dataAccess.py @@ -6,6 +6,7 @@ from src.document_sources.gcs_bucket import delete_file_from_gcs from src.shared.constants import BUCKET_UPLOAD from src.entities.source_node import sourceNode +from src.communities import MAX_COMMUNITY_LEVELS import json from dotenv import load_dotenv @@ -281,10 +282,23 @@ def delete_file_from_graph(self, filenames, source_types, deleteEntities:str, me match (c)-[:HAS_ENTITY]->(e) where not exists { (e)<-[:HAS_ENTITY]-()-[:PART_OF]->(d2) where not d2 in documents } detach delete e - """ + """ + query_to_delete_communities = """ + MATCH (c:`__Community__`) + WHERE NOT EXISTS { ()-[:IN_COMMUNITY]->(c) } AND c.level = 0 + DETACH DELETE c + + WITH * + UNWIND range(1, $max_level) AS level + MATCH (c:`__Community__`) + WHERE c.level = level AND NOT EXISTS { (c)<-[:PARENT_COMMUNITY]-(child) } + DETACH DELETE c + """ param = {"filename_list" : filename_list, "source_types_list": source_types_list} + community_param = {"max_level":MAX_COMMUNITY_LEVELS} if deleteEntities == "true": result = self.execute_query(query_to_delete_document_and_entities, param) + _ = self.execute_query(query_to_delete_communities,community_param) logging.info(f"Deleting {len(filename_list)} documents = '{filename_list}' from '{source_types_list}' from database") else : result = self.execute_query(query_to_delete_document, param) @@ -293,17 +307,29 @@ def delete_file_from_graph(self, filenames, source_types, deleteEntities:str, me def list_unconnected_nodes(self): query = """ - MATCH (e:!Chunk&!Document) - WHERE NOT exists { (e)--(:!Chunk&!Document) } - OPTIONAL MATCH (doc:Document)<-[:PART_OF]-(c:Chunk)-[:HAS_ENTITY]->(e) - RETURN e {.*, embedding:null, elementId:elementId(e), labels:labels(e)} as e, - collect(distinct doc.fileName) as documents, count(distinct c) as chunkConnections - ORDER BY e.id ASC - LIMIT 100 - """ + MATCH (e:!Chunk&!Document&!`__Community__`) + WHERE NOT exists { (e)--(:!Chunk&!Document&!`__Community__`) } + OPTIONAL MATCH (doc:Document)<-[:PART_OF]-(c:Chunk)-[:HAS_ENTITY]->(e) + RETURN + e { + .*, + embedding: null, + elementId: elementId(e), + labels: CASE + WHEN size(labels(e)) > 1 THEN + apoc.coll.removeAll(labels(e), ["__Entity__"]) + ELSE + ["Entity"] + END + } AS e, + collect(distinct doc.fileName) AS documents, + count(distinct c) AS chunkConnections + ORDER BY e.id ASC + LIMIT 100 + """ query_total_nodes = """ - MATCH (e:!Chunk&!Document) - WHERE NOT exists { (e)--(:!Chunk&!Document) } + MATCH (e:!Chunk&!Document&!`__Community__`) + WHERE NOT exists { (e)--(:!Chunk&!Document&!`__Community__`) } RETURN count(*) as total """ nodes_list = self.execute_query(query) @@ -323,9 +349,9 @@ def get_duplicate_nodes_list(self): score_value = float(os.environ.get('DUPLICATE_SCORE_VALUE')) text_distance = int(os.environ.get('DUPLICATE_TEXT_DISTANCE')) query_duplicate_nodes = """ - MATCH (n:!Chunk&!Document) with n - WHERE n.embedding is not null and n.id is not null // and size(n.id) > 3 - WITH n ORDER BY count {{ (n)--() }} DESC, size(n.id) DESC // updated + MATCH (n:!Chunk&!Document&!`__Community__`) with n + WHERE n.embedding is not null and n.id is not null // and size(toString(n.id)) > 3 + WITH n ORDER BY count {{ (n)--() }} DESC, size(toString(n.id)) DESC // updated WITH collect(n) as nodes UNWIND nodes as n WITH n, [other in nodes @@ -335,9 +361,9 @@ def get_duplicate_nodes_list(self): AND ( // either contains each other as substrings or has a text edit distinct of less than 3 - (size(other.id) > 2 AND toLower(n.id) CONTAINS toLower(other.id)) OR - (size(n.id) > 2 AND toLower(other.id) CONTAINS toLower(n.id)) - OR (size(n.id)>5 AND apoc.text.distance(toLower(n.id), toLower(other.id)) < $duplicate_text_distance) + (size(toString(other.id)) > 2 AND toLower(n.id) CONTAINS toLower(other.id)) OR + (size(toString(n.id)) > 2 AND toLower(other.id) CONTAINS toLower(n.id)) + OR (size(toString(n.id))>5 AND apoc.text.distance(toLower(n.id), toLower(other.id)) < $duplicate_text_distance) OR vector.similarity.cosine(other.embedding, n.embedding) > $duplicate_score_value )] as similar diff --git a/backend/src/post_processing.py b/backend/src/post_processing.py index 88d99385a..22af50b76 100644 --- a/backend/src/post_processing.py +++ b/backend/src/post_processing.py @@ -16,6 +16,55 @@ COMMUNITY_INDEX_DROP_QUERY = "DROP INDEX community_keyword IF EXISTS;" COMMUNITY_INDEX_FULL_TEXT_QUERY = "CREATE FULLTEXT INDEX community_keyword FOR (n:`__Community__`) ON EACH [n.summary]" +CHUNK_VECTOR_INDEX_NAME = "vector" +CHUNK_VECTOR_EMBEDDING_DIMENSION = 384 + +DROP_CHUNK_VECTOR_INDEX_QUERY = f"DROP INDEX {CHUNK_VECTOR_INDEX_NAME} IF EXISTS;" +CREATE_CHUNK_VECTOR_INDEX_QUERY = """ +CREATE VECTOR INDEX {index_name} IF NOT EXISTS FOR (c:Chunk) ON c.embedding +OPTIONS {{ + indexConfig: {{ + `vector.dimensions`: {embedding_dimension}, + `vector.similarity_function`: 'cosine' + }} +}} +""" + +def create_vector_index(driver, index_type, embedding_dimension=None): + drop_query = "" + query = "" + + if index_type == CHUNK_VECTOR_INDEX_NAME: + drop_query = DROP_CHUNK_VECTOR_INDEX_QUERY + query = CREATE_CHUNK_VECTOR_INDEX_QUERY.format( + index_name=CHUNK_VECTOR_INDEX_NAME, + embedding_dimension=embedding_dimension if embedding_dimension else CHUNK_VECTOR_EMBEDDING_DIMENSION + ) + else: + logging.error(f"Invalid index type provided: {index_type}") + return + + try: + logging.info("Starting the process to create vector index.") + with driver.session() as session: + try: + start_step = time.time() + session.run(drop_query) + logging.info(f"Dropped existing index (if any) in {time.time() - start_step:.2f} seconds.") + except Exception as e: + logging.error(f"Failed to drop index: {e}") + return + + try: + start_step = time.time() + session.run(query) + logging.info(f"Created vector index in {time.time() - start_step:.2f} seconds.") + except Exception as e: + logging.error(f"Failed to create vector index: {e}") + return + except Exception as e: + logging.error("An error occurred while creating the vector index.", exc_info=True) + logging.error(f"Error details: {str(e)}") def create_fulltext(driver,type): @@ -70,8 +119,8 @@ def create_fulltext(driver,type): logging.info(f"Process completed in {time.time() - start_time:.2f} seconds.") -def create_fulltext_indexes(uri, username, password, database): - types = ["entities", "hybrid", "community"] +def create_vector_fulltext_indexes(uri, username, password, database): + types = ["entities", "hybrid"] logging.info("Starting the process of creating full-text indexes.") try: @@ -79,7 +128,7 @@ def create_fulltext_indexes(uri, username, password, database): driver.verify_connectivity() logging.info("Database connectivity verified.") except Exception as e: - logging.error(f"An unexpected error occurred: {e}") + logging.error(f"Error connecting to the database: {e}") return for index_type in types: @@ -90,11 +139,22 @@ def create_fulltext_indexes(uri, username, password, database): except Exception as e: logging.error(f"Failed to create full-text index for type '{index_type}': {e}") - logging.info("Full-text indexes creation process completed.") - driver.close() - logging.info("Driver closed.") - - + try: + logging.info(f"Creating a vector index for type '{CHUNK_VECTOR_INDEX_NAME}'.") + create_vector_index(driver, CHUNK_VECTOR_INDEX_NAME,CHUNK_VECTOR_EMBEDDING_DIMENSION) + logging.info("Vector index for chunk created successfully.") + except Exception as e: + logging.error(f"Failed to create vector index for '{CHUNK_VECTOR_INDEX_NAME}': {e}") + + try: + driver.close() + logging.info("Driver closed successfully.") + except Exception as e: + logging.error(f"Error closing the driver: {e}") + + logging.info("Full-text and vector index creation process completed.") + + def create_entity_embedding(graph:Neo4jGraph): rows = fetch_entities_for_embedding(graph) for i in range(0, len(rows), 1000): diff --git a/backend/src/shared/constants.py b/backend/src/shared/constants.py index 834459fd1..20bbffa3f 100644 --- a/backend/src/shared/constants.py +++ b/backend/src/shared/constants.py @@ -219,7 +219,7 @@ QUESTION_TRANSFORM_TEMPLATE = "Given the below conversation, generate a search query to look up in order to get information relevant to the conversation. Only respond with the query, nothing else." ## CHAT QUERIES -VECTOR_SEARCH_TOP_K = 10 +VECTOR_SEARCH_TOP_K = 5 VECTOR_SEARCH_QUERY = """ WITH node AS chunk, score @@ -246,11 +246,11 @@ """ ### Vector graph search -VECTOR_GRAPH_SEARCH_ENTITY_LIMIT = 25 +VECTOR_GRAPH_SEARCH_ENTITY_LIMIT = 40 VECTOR_GRAPH_SEARCH_EMBEDDING_MIN_MATCH = 0.3 VECTOR_GRAPH_SEARCH_EMBEDDING_MAX_MATCH = 0.9 -VECTOR_GRAPH_SEARCH_ENTITY_LIMIT_MINMAX_CASE = 10 -VECTOR_GRAPH_SEARCH_ENTITY_LIMIT_MAX_CASE = 25 +VECTOR_GRAPH_SEARCH_ENTITY_LIMIT_MINMAX_CASE = 20 +VECTOR_GRAPH_SEARCH_ENTITY_LIMIT_MAX_CASE = 40 VECTOR_GRAPH_SEARCH_QUERY_PREFIX = """ WITH node as chunk, score From 7f255eee875d576ba370f29a32d29fc780e6910a Mon Sep 17 00:00:00 2001 From: aashipandya <156318202+aashipandya@users.noreply.github.com> Date: Wed, 9 Oct 2024 11:37:18 +0530 Subject: [PATCH 156/292] Async way to create entities from multiple chunks (#788) * LLMs with latest langchain dev libraries * conflict resolved * all llm models with latest library changes * async way to get graph documents * indentation correction --- backend/score.py | 18 ++++++------------ backend/src/llm.py | 32 ++++++++++++++++---------------- backend/src/main.py | 44 ++++++++++++++++++++++---------------------- 3 files changed, 44 insertions(+), 50 deletions(-) diff --git a/backend/score.py b/backend/score.py index 7bc62d186..2908c89ea 100644 --- a/backend/score.py +++ b/backend/score.py @@ -178,28 +178,22 @@ async def extract_knowledge_graph_from_file( if source_type == 'local file': merged_file_path = os.path.join(MERGED_DIR,file_name) logging.info(f'File path:{merged_file_path}') - result = await asyncio.to_thread( - extract_graph_from_file_local_file, uri, userName, password, database, model, merged_file_path, file_name, allowedNodes, allowedRelationship, retry_condition) + result = await extract_graph_from_file_local_file(uri, userName, password, database, model, merged_file_path, file_name, allowedNodes, allowedRelationship, retry_condition) elif source_type == 's3 bucket' and source_url: - result = await asyncio.to_thread( - extract_graph_from_file_s3, uri, userName, password, database, model, source_url, aws_access_key_id, aws_secret_access_key, file_name, allowedNodes, allowedRelationship, retry_condition) + result = await extract_graph_from_file_s3(uri, userName, password, database, model, source_url, aws_access_key_id, aws_secret_access_key, file_name, allowedNodes, allowedRelationship, retry_condition) elif source_type == 'web-url': - result = await asyncio.to_thread( - extract_graph_from_web_page, uri, userName, password, database, model, source_url, file_name, allowedNodes, allowedRelationship, retry_condition) + result = await extract_graph_from_web_page(uri, userName, password, database, model, source_url, file_name, allowedNodes, allowedRelationship, retry_condition) elif source_type == 'youtube' and source_url: - result = await asyncio.to_thread( - extract_graph_from_file_youtube, uri, userName, password, database, model, source_url, file_name, allowedNodes, allowedRelationship, retry_condition) + result = await extract_graph_from_file_youtube(uri, userName, password, database, model, source_url, file_name, allowedNodes, allowedRelationship, retry_condition) elif source_type == 'Wikipedia' and wiki_query: - result = await asyncio.to_thread( - extract_graph_from_file_Wikipedia, uri, userName, password, database, model, wiki_query, language, file_name, allowedNodes, allowedRelationship, retry_condition) + result = await extract_graph_from_file_Wikipedia(uri, userName, password, database, model, wiki_query, language, file_name, allowedNodes, allowedRelationship, retry_condition) elif source_type == 'gcs bucket' and gcs_bucket_name: - result = await asyncio.to_thread( - extract_graph_from_file_gcs, uri, userName, password, database, model, gcs_project_id, gcs_bucket_name, gcs_bucket_folder, gcs_blob_filename, access_token, file_name, allowedNodes, allowedRelationship, retry_condition) + result = await extract_graph_from_file_gcs(uri, userName, password, database, model, gcs_project_id, gcs_bucket_name, gcs_bucket_folder, gcs_blob_filename, access_token, file_name, allowedNodes, allowedRelationship, retry_condition) else: return create_api_response('Failed',message='source_type is other than accepted source') extract_api_time = time.time() - start_time diff --git a/backend/src/llm.py b/backend/src/llm.py index c2335685f..c7c6b36e2 100644 --- a/backend/src/llm.py +++ b/backend/src/llm.py @@ -141,7 +141,7 @@ def get_combined_chunks(chunkId_chunkDoc_list): return combined_chunk_document_list -def get_graph_document_list( +async def get_graph_document_list( llm, combined_chunk_document_list, allowedNodes, allowedRelationship ): futures = [] @@ -165,23 +165,23 @@ def get_graph_document_list( ignore_tool_usage=True, #prompt = ChatPromptTemplate.from_messages(["system",PROMPT_TO_ALL_LLMs]) ) - with ThreadPoolExecutor(max_workers=10) as executor: - for chunk in combined_chunk_document_list: - chunk_doc = Document( - page_content=chunk.page_content.encode("utf-8"), metadata=chunk.metadata - ) - futures.append( - executor.submit(llm_transformer.convert_to_graph_documents, [chunk_doc]) - ) - - for i, future in enumerate(concurrent.futures.as_completed(futures)): - graph_document = future.result() - graph_document_list.append(graph_document[0]) - + # with ThreadPoolExecutor(max_workers=10) as executor: + # for chunk in combined_chunk_document_list: + # chunk_doc = Document( + # page_content=chunk.page_content.encode("utf-8"), metadata=chunk.metadata + # ) + # futures.append( + # executor.submit(llm_transformer.convert_to_graph_documents, [chunk_doc]) + # ) + + # for i, future in enumerate(concurrent.futures.as_completed(futures)): + # graph_document = future.result() + # graph_document_list.append(graph_document[0]) + graph_document_list = await llm_transformer.aconvert_to_graph_documents(combined_chunk_document_list) return graph_document_list -def get_graph_from_llm(model, chunkId_chunkDoc_list, allowedNodes, allowedRelationship): +async def get_graph_from_llm(model, chunkId_chunkDoc_list, allowedNodes, allowedRelationship): llm, model_name = get_llm(model) combined_chunk_document_list = get_combined_chunks(chunkId_chunkDoc_list) @@ -195,7 +195,7 @@ def get_graph_from_llm(model, chunkId_chunkDoc_list, allowedNodes, allowedRelati else: allowedRelationship = allowedRelationship.split(',') - graph_document_list = get_graph_document_list( + graph_document_list = await get_graph_document_list( llm, combined_chunk_document_list, allowedNodes, allowedRelationship ) return graph_document_list diff --git a/backend/src/main.py b/backend/src/main.py index 731ff56e5..8b95b2e88 100644 --- a/backend/src/main.py +++ b/backend/src/main.py @@ -208,7 +208,7 @@ def create_source_node_graph_url_wikipedia(graph, model, wiki_query, source_type lst_file_name.append({'fileName':obj_source_node.file_name,'fileSize':obj_source_node.file_size,'url':obj_source_node.url, 'language':obj_source_node.language, 'status':'Success'}) return lst_file_name,success_count,failed_count -def extract_graph_from_file_local_file(uri, userName, password, database, model, merged_file_path, fileName, allowedNodes, allowedRelationship, retry_condition): +async def extract_graph_from_file_local_file(uri, userName, password, database, model, merged_file_path, fileName, allowedNodes, allowedRelationship, retry_condition): logging.info(f'Process file name :{fileName}') if retry_condition is None: @@ -220,11 +220,11 @@ def extract_graph_from_file_local_file(uri, userName, password, database, model, file_name, pages, file_extension = get_documents_from_file_by_path(merged_file_path,fileName) if pages==None or len(pages)==0: raise Exception(f'File content is not available for file : {file_name}') - return processing_source(uri, userName, password, database, model, file_name, pages, allowedNodes, allowedRelationship, True, merged_file_path) + return await processing_source(uri, userName, password, database, model, file_name, pages, allowedNodes, allowedRelationship, True, merged_file_path) else: - return processing_source(uri, userName, password, database, model, fileName, [], allowedNodes, allowedRelationship, True, merged_file_path, retry_condition) + return await processing_source(uri, userName, password, database, model, fileName, [], allowedNodes, allowedRelationship, True, merged_file_path, retry_condition) -def extract_graph_from_file_s3(uri, userName, password, database, model, source_url, aws_access_key_id, aws_secret_access_key, file_name, allowedNodes, allowedRelationship, retry_condition): +async def extract_graph_from_file_s3(uri, userName, password, database, model, source_url, aws_access_key_id, aws_secret_access_key, file_name, allowedNodes, allowedRelationship, retry_condition): if retry_condition is None: if(aws_access_key_id==None or aws_secret_access_key==None): raise Exception('Please provide AWS access and secret keys') @@ -234,49 +234,49 @@ def extract_graph_from_file_s3(uri, userName, password, database, model, source_ if pages==None or len(pages)==0: raise Exception(f'File content is not available for file : {file_name}') - return processing_source(uri, userName, password, database, model, file_name, pages, allowedNodes, allowedRelationship) + return await processing_source(uri, userName, password, database, model, file_name, pages, allowedNodes, allowedRelationship) else: - return processing_source(uri, userName, password, database, model, file_name, [], allowedNodes, allowedRelationship, retry_condition=retry_condition) + return await processing_source(uri, userName, password, database, model, file_name, [], allowedNodes, allowedRelationship, retry_condition=retry_condition) -def extract_graph_from_web_page(uri, userName, password, database, model, source_url, file_name, allowedNodes, allowedRelationship, retry_condition): +async def extract_graph_from_web_page(uri, userName, password, database, model, source_url, file_name, allowedNodes, allowedRelationship, retry_condition): if retry_condition is None: file_name, pages = get_documents_from_web_page(source_url) if pages==None or len(pages)==0: raise Exception(f'Content is not available for given URL : {file_name}') - return processing_source(uri, userName, password, database, model, file_name, pages, allowedNodes, allowedRelationship) + return await processing_source(uri, userName, password, database, model, file_name, pages, allowedNodes, allowedRelationship) else: - return processing_source(uri, userName, password, database, model, file_name, [], allowedNodes, allowedRelationship, retry_condition=retry_condition) + return await processing_source(uri, userName, password, database, model, file_name, [], allowedNodes, allowedRelationship, retry_condition=retry_condition) -def extract_graph_from_file_youtube(uri, userName, password, database, model, source_url, file_name, allowedNodes, allowedRelationship, retry_condition): +async def extract_graph_from_file_youtube(uri, userName, password, database, model, source_url, file_name, allowedNodes, allowedRelationship, retry_condition): if retry_condition is None: file_name, pages = get_documents_from_youtube(source_url) if pages==None or len(pages)==0: raise Exception(f'Youtube transcript is not available for file : {file_name}') - return processing_source(uri, userName, password, database, model, file_name, pages, allowedNodes, allowedRelationship) + return await processing_source(uri, userName, password, database, model, file_name, pages, allowedNodes, allowedRelationship) else: - return processing_source(uri, userName, password, database, model, file_name, [], allowedNodes, allowedRelationship, retry_condition=retry_condition) + return await processing_source(uri, userName, password, database, model, file_name, [], allowedNodes, allowedRelationship, retry_condition=retry_condition) -def extract_graph_from_file_Wikipedia(uri, userName, password, database, model, wiki_query, language, file_name, allowedNodes, allowedRelationship, retry_condition): +async def extract_graph_from_file_Wikipedia(uri, userName, password, database, model, wiki_query, language, file_name, allowedNodes, allowedRelationship, retry_condition): if retry_condition is None: file_name, pages = get_documents_from_Wikipedia(wiki_query, language) if pages==None or len(pages)==0: raise Exception(f'Wikipedia page is not available for file : {file_name}') - return processing_source(uri, userName, password, database, model, file_name, pages, allowedNodes, allowedRelationship) + return await processing_source(uri, userName, password, database, model, file_name, pages, allowedNodes, allowedRelationship) else: - return processing_source(uri, userName, password, database, model, file_name,[], allowedNodes, allowedRelationship, retry_condition=retry_condition) + return await processing_source(uri, userName, password, database, model, file_name,[], allowedNodes, allowedRelationship, retry_condition=retry_condition) -def extract_graph_from_file_gcs(uri, userName, password, database, model, gcs_project_id, gcs_bucket_name, gcs_bucket_folder, gcs_blob_filename, access_token, file_name, allowedNodes, allowedRelationship, retry_condition): +async def extract_graph_from_file_gcs(uri, userName, password, database, model, gcs_project_id, gcs_bucket_name, gcs_bucket_folder, gcs_blob_filename, access_token, file_name, allowedNodes, allowedRelationship, retry_condition): if retry_condition is None: file_name, pages = get_documents_from_gcs(gcs_project_id, gcs_bucket_name, gcs_bucket_folder, gcs_blob_filename, access_token) if pages==None or len(pages)==0: raise Exception(f'File content is not available for file : {file_name}') - return processing_source(uri, userName, password, database, model, file_name, pages, allowedNodes, allowedRelationship) + return await processing_source(uri, userName, password, database, model, file_name, pages, allowedNodes, allowedRelationship) else: - return processing_source(uri, userName, password, database, model, file_name, [], allowedNodes, allowedRelationship, retry_condition=retry_condition) + return await processing_source(uri, userName, password, database, model, file_name, [], allowedNodes, allowedRelationship, retry_condition=retry_condition) -def processing_source(uri, userName, password, database, model, file_name, pages, allowedNodes, allowedRelationship, is_uploaded_from_local=None, merged_file_path=None, retry_condition=None): +async def processing_source(uri, userName, password, database, model, file_name, pages, allowedNodes, allowedRelationship, is_uploaded_from_local=None, merged_file_path=None, retry_condition=None): """ Extracts a Neo4jGraph from a PDF file based on the model. @@ -366,7 +366,7 @@ def processing_source(uri, userName, password, database, model, file_name, pages break else: processing_chunks_start_time = time.time() - node_count,rel_count,latency_processed_chunk = processing_chunks(selected_chunks,graph,uri, userName, password, database,file_name,model,allowedNodes,allowedRelationship,node_count, rel_count) + node_count,rel_count,latency_processed_chunk = await processing_chunks(selected_chunks,graph,uri, userName, password, database,file_name,model,allowedNodes,allowedRelationship,node_count, rel_count) processing_chunks_end_time = time.time() processing_chunks_elapsed_end_time = processing_chunks_end_time - processing_chunks_start_time logging.info(f"Time taken {update_graph_chunk_processed} chunks processed upto {select_chunks_upto} completed in {processing_chunks_elapsed_end_time:.2f} seconds for file name {file_name}") @@ -439,7 +439,7 @@ def processing_source(uri, userName, password, database, model, file_name, pages logging.error(error_message) raise Exception(error_message) -def processing_chunks(chunkId_chunkDoc_list,graph,uri, userName, password, database,file_name,model,allowedNodes,allowedRelationship, node_count, rel_count): +async def processing_chunks(chunkId_chunkDoc_list,graph,uri, userName, password, database,file_name,model,allowedNodes,allowedRelationship, node_count, rel_count): #create vector index and update chunk node with embedding if graph is not None: if graph._driver._closed: @@ -456,7 +456,7 @@ def processing_chunks(chunkId_chunkDoc_list,graph,uri, userName, password, datab logging.info("Get graph document list from models") start_entity_extraction = time.time() - graph_documents = get_graph_from_llm(model, chunkId_chunkDoc_list, allowedNodes, allowedRelationship) + graph_documents = await get_graph_from_llm(model, chunkId_chunkDoc_list, allowedNodes, allowedRelationship) end_entity_extraction = time.time() elapsed_entity_extraction = end_entity_extraction - start_entity_extraction logging.info(f'Time taken to extract enitities from LLM Graph Builder: {elapsed_entity_extraction:.2f} seconds') From 943f5392ad377ddaf88445119b71be2a722476df Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Thu, 10 Oct 2024 12:29:12 +0530 Subject: [PATCH 157/292] fixed graph mode error (#792) --- backend/score.py | 5 +++-- backend/src/QA_integration.py | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/backend/score.py b/backend/score.py index 2908c89ea..221e58b61 100644 --- a/backend/score.py +++ b/backend/score.py @@ -300,8 +300,9 @@ async def chat_bot(uri=Form(),model=Form(None),userName=Form(), password=Form(), graph = Neo4jGraph( url=uri,username=userName,password=password,database=database,sanitize = True, refresh_schema=True) else: graph = create_graph_database_connection(uri, userName, password, database) - graph_DB_dataAccess = graphDBdataAccess(graph) - write_access = graph_DB_dataAccess.check_account_access(database=database) + + graph_DB_dataAccess = graphDBdataAccess(graph) + write_access = graph_DB_dataAccess.check_account_access(database=database) result = await asyncio.to_thread(QA_RAG,graph=graph,model=model,question=question,document_names=document_names,session_id=session_id,mode=mode,write_access=write_access) total_call_time = time.time() - qa_rag_start_time diff --git a/backend/src/QA_integration.py b/backend/src/QA_integration.py index 169d2b8c3..d0c0fa9f4 100644 --- a/backend/src/QA_integration.py +++ b/backend/src/QA_integration.py @@ -505,6 +505,7 @@ def create_graph_chain(model, graph): validate_cypher= True, graph=graph, # verbose=True, + allow_dangerous_requests=True, return_intermediate_steps = True, top_k=3 ) From 126dd4800b7e792f833b91f3954488ad2c51fac2 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Thu, 10 Oct 2024 13:05:02 +0530 Subject: [PATCH 158/292] Raga's Evaluation Metrics (#787) * added Multi modes selection * ragas eval * added response * multimodes state mangement * fix: state handling of chat details of the default mode * Added the ChatModeSwitch Component * modes switch statemangement * added the chatmodes switch in both view * removed the copied text * Handled the error scenario * fix: speech issue between modes * ragas evaluation metric show * Output return type changed * fix: Handled activespeech speech and othermessage modes switch * used requestanimationframe instead of setTimeOut * removed the commented code * Added ragas to requirements * Integrated the metric api * ragas response updated, llm list updated * resolved syntax error in score * Added the Metrics Table * fix: Long text UI Issue * code optimization for evaluation * added the download button for downloading the info * key name change * Optimized the downloadClickHandler --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kaustubh-darekar Co-authored-by: a-s-poorna --- backend/requirements.txt | 1 + backend/score.py | 20 ++- backend/src/QA_integration.py | 43 +++-- backend/src/ragas_eval.py | 150 ++++++++++++++++++ .../src/components/ChatBot/ChatInfoModal.tsx | 87 ++++++---- frontend/src/components/ChatBot/Chatbot.tsx | 140 ++++++++++++++-- .../src/components/ChatBot/MetricsTab.tsx | 113 +++++++++++++ frontend/src/services/GetRagasMetric.ts | 17 ++ frontend/src/types.ts | 34 ++++ 9 files changed, 550 insertions(+), 55 deletions(-) create mode 100644 backend/src/ragas_eval.py create mode 100644 frontend/src/components/ChatBot/MetricsTab.tsx create mode 100644 frontend/src/services/GetRagasMetric.ts diff --git a/backend/requirements.txt b/backend/requirements.txt index 30b767939..8fc0e0bda 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -179,4 +179,5 @@ PyMuPDF==1.24.5 pypandoc==1.13 graphdatascience==1.10 Secweb==1.11.0 +ragas==0.1.14 diff --git a/backend/score.py b/backend/score.py index 221e58b61..920fa00f9 100644 --- a/backend/score.py +++ b/backend/score.py @@ -33,6 +33,8 @@ from Secweb.XContentTypeOptions import XContentTypeOptions from Secweb.XFrameOptions import XFrame +from src.ragas_eval import * + logger = CustomLogger() CHUNK_DIR = os.path.join(os.path.dirname(__file__), "chunks") MERGED_DIR = os.path.join(os.path.dirname(__file__), "merged_files") @@ -706,7 +708,23 @@ async def retry_processing(uri=Form(), userName=Form(), password=Form(), databas logging.exception(f'{error_message}') return create_api_response(job_status, message=message, error=error_message) finally: - gc.collect() + gc.collect() + +@app.post('/metric') +async def calculate_metric(question=Form(),context=Form(),answer=Form(),model=Form()): + try: + result = await asyncio.to_thread(get_ragas_metrics,question,context,answer,model) + if result is None: + return create_api_response('Failed', message='Failed to calculate metrics.',error="Ragas evaluation returned null") + return create_api_response('Success',data=result,message=f"Status set to Reprocess for filename : {result}") + except Exception as e: + job_status = "Failed" + message="Error while calculating evaluation metrics" + error_message = str(e) + logging.exception(f'{error_message}') + return create_api_response(job_status, message=message, error=error_message) + finally: + gc.collect() if __name__ == "__main__": uvicorn.run(app) diff --git a/backend/src/QA_integration.py b/backend/src/QA_integration.py index d0c0fa9f4..30375a9d9 100644 --- a/backend/src/QA_integration.py +++ b/backend/src/QA_integration.py @@ -22,7 +22,8 @@ from langchain_text_splitters import TokenTextSplitter from langchain_core.messages import HumanMessage, AIMessage from langchain.chains import GraphCypherQAChain -from langchain_community.chat_message_histories import ChatMessageHistory +from langchain_community.chat_message_histories import ChatMessageHistory +from langchain_core.callbacks import StdOutCallbackHandler, BaseCallbackHandler # LangChain chat models from langchain_openai import ChatOpenAI, AzureChatOpenAI @@ -38,13 +39,12 @@ from src.shared.common_fn import load_embedding_model from src.shared.constants import * from src.graphDB_dataAccess import graphDBdataAccess +from src.ragas_eval import get_ragas_metrics load_dotenv() EMBEDDING_MODEL = os.getenv('EMBEDDING_MODEL') EMBEDDING_FUNCTION , _ = load_embedding_model(EMBEDDING_MODEL) - - class SessionChatHistory: history_dict = {} @@ -58,6 +58,17 @@ def get_chat_history(cls, session_id): logging.info(f"Retrieved existing ChatMessageHistory Local for session ID: {session_id}") return cls.history_dict[session_id] +class CustomCallback(BaseCallbackHandler): + + def __init__(self): + self.transformed_question = None + + def on_llm_end( + self,response, **kwargs: Any + ) -> None: + logging.info("question transformed") + self.transformed_question = response.generations[0][0].text.strip() + def get_history_by_session_id(session_id): try: return SessionChatHistory.get_chat_history(session_id) @@ -250,13 +261,17 @@ def process_documents(docs, question, messages, llm, model,chat_mode_settings): logging.error(f"Error processing documents: {e}") raise - return content, result, total_tokens + return content, result, total_tokens, formatted_docs def retrieve_documents(doc_retriever, messages): start_time = time.time() try: - docs = doc_retriever.invoke({"messages": messages}) + handler = CustomCallback() + docs = doc_retriever.invoke({"messages": messages},{"callbacks":[handler]}) + transformed_question = handler.transformed_question + if transformed_question: + logging.info(f"Transformed question : {transformed_question}") doc_retrieval_time = time.time() - start_time logging.info(f"Documents retrieved in {doc_retrieval_time:.2f} seconds") @@ -264,7 +279,7 @@ def retrieve_documents(doc_retriever, messages): logging.error(f"Error retrieving documents: {e}") raise - return docs + return docs,transformed_question def create_document_retriever_chain(llm, retriever): try: @@ -408,14 +423,19 @@ def process_chat_response(messages, history, question, model, graph, document_na try: llm, doc_retriever, model_version = setup_chat(model, graph, document_names, chat_mode_settings) - docs = retrieve_documents(doc_retriever, messages) + docs,transformed_question = retrieve_documents(doc_retriever, messages) if docs: - content, result, total_tokens = process_documents(docs, question, messages, llm, model, chat_mode_settings) + content, result, total_tokens,formatted_docs = process_documents(docs, question, messages, llm, model, chat_mode_settings) else: content = "I couldn't find any relevant documents to answer your question." result = {"sources": list(), "nodedetails": list(), "entities": list()} total_tokens = 0 + formatted_docs = "" + + question = transformed_question if transformed_question else question + # metrics = get_ragas_metrics(question,formatted_docs,content) + # print(metrics) ai_response = AIMessage(content=content) messages.append(ai_response) @@ -424,11 +444,12 @@ def process_chat_response(messages, history, question, model, graph, document_na summarization_thread.start() logging.info("Summarization thread started.") # summarize_and_log(history, messages, llm) - + metric_details = {"question":question,"contexts":formatted_docs,"answer":content} return { "session_id": "", "message": content, "info": { + # "metrics" : metrics, "sources": result["sources"], "model": model_version, "nodedetails": result["nodedetails"], @@ -436,7 +457,9 @@ def process_chat_response(messages, history, question, model, graph, document_na "response_time": 0, "mode": chat_mode_settings["mode"], "entities": result["entities"], + "metric_details": metric_details, }, + "user": "chatbot" } @@ -446,6 +469,7 @@ def process_chat_response(messages, history, question, model, graph, document_na "session_id": "", "message": "Something went wrong", "info": { + "metrics" : [], "sources": [], "nodedetails": [], "total_tokens": 0, @@ -453,6 +477,7 @@ def process_chat_response(messages, history, question, model, graph, document_na "error": f"{type(e).__name__}: {str(e)}", "mode": chat_mode_settings["mode"], "entities": [], + "metric_details": {}, }, "user": "chatbot" } diff --git a/backend/src/ragas_eval.py b/backend/src/ragas_eval.py new file mode 100644 index 000000000..940a809dc --- /dev/null +++ b/backend/src/ragas_eval.py @@ -0,0 +1,150 @@ +import os +import logging +import time +from typing import Dict, Tuple, Optional +import boto3 +from datasets import Dataset +from dotenv import load_dotenv +from langchain_anthropic import ChatAnthropic +from langchain_aws import ChatBedrock +from langchain_community.chat_models import ChatOllama +from langchain_experimental.graph_transformers.diffbot import DiffbotGraphTransformer +from langchain_fireworks import ChatFireworks +from langchain_google_vertexai import ( + ChatVertexAI, + HarmBlockThreshold, + HarmCategory, +) +from langchain_groq import ChatGroq +from langchain_openai import AzureChatOpenAI, ChatOpenAI +from ragas import evaluate +from ragas.metrics import answer_relevancy, context_utilization, faithfulness +from src.shared.common_fn import load_embedding_model + +load_dotenv() + +# Constants for clarity and maintainability +RAGAS_MODEL_VERSIONS = { + "openai-gpt-3.5": "gpt-3.5-turbo-16k", + "gemini-1.0-pro": "gemini-1.0-pro-001", + "gemini-1.5-pro": "gemini-1.5-pro-002", + "gemini-1.5-flash": "gemini-1.5-flash-002", + "openai-gpt-4": "gpt-4-turbo-2024-04-09", + "openai-gpt-4o-mini": "gpt-4o-mini-2024-07-18", + "openai-gpt-4o": "gpt-4o-mini-2024-07-18", + "diffbot": "gpt-4-turbo-2024-04-09", + "groq-llama3": "groq_llama3_70b", +} + +EMBEDDING_MODEL = os.getenv("EMBEDDING_MODEL") +EMBEDDING_FUNCTION, _ = load_embedding_model(EMBEDDING_MODEL) + + +def get_ragas_llm(model: str) -> Tuple[object, str]: + """Retrieves the specified language model. Improved error handling and structure.""" + env_key = f"LLM_MODEL_CONFIG_{model}" + env_value = os.environ.get(env_key) + logging.info(f"Loading model configuration: {env_key}") + try: + if "gemini" in model: + credentials, project_id = google.auth.default() + model_name = RAGAS_MODEL_VERSIONS[model] + llm = ChatVertexAI( + model_name=model_name, + credentials=credentials, + project=project_id, + temperature=0, + safety_settings={ + #setting safety to NONE for all categories. Consider reviewing this for production systems + HarmCategory.HARM_CATEGORY_UNSPECIFIED: HarmBlockThreshold.BLOCK_NONE, + HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: HarmBlockThreshold.BLOCK_NONE, + HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_NONE, + HarmCategory.HARM_CATEGORY_HARASSMENT: HarmBlockThreshold.BLOCK_NONE, + HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: HarmBlockThreshold.BLOCK_NONE, + }, + ) + elif "openai" in model: + model_name = RAGAS_MODEL_VERSIONS[model] + llm = ChatOpenAI( + api_key=os.environ.get("OPENAI_API_KEY"), model=model_name, temperature=0 + ) + + elif "azure" in model: + model_name, api_endpoint, api_key, api_version = env_value.split(",") + llm = AzureChatOpenAI( + api_key=api_key, + azure_endpoint=api_endpoint, + azure_deployment=model_name, + api_version=api_version, + temperature=0, + ) + elif "anthropic" in model: + model_name, api_key = env_value.split(",") + llm = ChatAnthropic(api_key=api_key, model=model_name, temperature=0) + elif "fireworks" in model: + model_name, api_key = env_value.split(",") + llm = ChatFireworks(api_key=api_key, model=model_name) + elif "groq" in model: + model_name, base_url, api_key = env_value.split(",") + llm = ChatGroq(api_key=api_key, model_name=model_name, temperature=0) + elif "bedrock" in model: + model_name, aws_access_key, aws_secret_key, region_name = env_value.split(",") + bedrock_client = boto3.client( + service_name="bedrock-runtime", + region_name=region_name, + aws_access_key_id=aws_access_key, + aws_secret_access_key=aws_secret_key, + ) + llm = ChatBedrock( + client=bedrock_client, model_id=model_name, model_kwargs=dict(temperature=0) + ) + elif "ollama" in model: + model_name, base_url = env_value.split(",") + llm = ChatOllama(base_url=base_url, model=model_name) + elif "diffbot" in model: + llm = DiffbotGraphTransformer( + diffbot_api_key=os.environ.get("DIFFBOT_API_KEY"), + extract_types=["entities", "facts"], + ) + else: + raise ValueError(f"Unsupported model: {model}") + + logging.info(f"Model loaded - Model Version: {model}") + return llm, model_name + except (ValueError, KeyError) as e: + logging.error(f"Error loading LLM: {e}") + raise + + +def get_ragas_metrics( + question: str, context: str, answer: str, model: str +) -> Optional[Dict[str, float]]: + """Calculates RAGAS metrics.""" + try: + start_time = time.time() + dataset = Dataset.from_dict( + {"question": [question], "answer": [answer], "contexts": [[context]]} + ) + logging.info("Dataset created successfully.") + + llm, model_name = get_ragas_llm(model=model) + logging.info(f"Evaluating with model: {model_name}") + + score = evaluate( + dataset=dataset, + metrics=[faithfulness, answer_relevancy, context_utilization], + llm=llm, + embeddings=EMBEDDING_FUNCTION, + ) + + score_dict = ( + score.to_pandas()[["faithfulness", "answer_relevancy", "context_utilization"]] + .round(4) + .to_dict(orient="records")[0] + ) + end_time = time.time() + logging.info(f"Evaluation completed in: {end_time - start_time:.2f} seconds") + return score_dict + except Exception as e: + logging.exception(f"Error during metrics evaluation: {e}") + return None \ No newline at end of file diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index 894833884..199d9eb6d 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -12,15 +12,7 @@ import { import { DocumentDuplicateIconOutline, ClipboardDocumentCheckIconOutline } from '@neo4j-ndl/react/icons'; import '../../styling/info.css'; import Neo4jRetrievalLogo from '../../assets/images/Neo4jRetrievalLogo.png'; -import { - Chunk, - Community, - Entity, - ExtendedNode, - ExtendedRelationship, - UserCredentials, - chatInfoMessage, -} from '../../types'; +import { Entity, ExtendedNode, UserCredentials, chatInfoMessage } from '../../types'; import { useContext, useEffect, useMemo, useState } from 'react'; import GraphViewButton from '../Graph/GraphViewButton'; import { chunkEntitiesAPI } from '../../services/ChunkEntitiesInfo'; @@ -33,6 +25,8 @@ import SourcesInfo from './SourcesInfo'; import CommunitiesInfo from './Communities'; import { chatModeLables } from '../../utils/Constants'; import { Relationship } from '@neo4j-nvl/base'; +import { getChatMetrics } from '../../services/GetRagasMetric'; +import MetricsTab from './MetricsTab'; const ChatInfoModal: React.FC = ({ sources, @@ -45,19 +39,33 @@ const ChatInfoModal: React.FC = ({ graphonly_entities, error, entities_ids, + metricanswer, + metriccontexts, + metricquestion, + metricmodel, + saveNodes, + saveChunks, + saveChatRelationships, + saveCommunities, + saveInfoEntitites, + saveMetrics, + toggleInfoLoading, + toggleMetricsLoading, + nodes, + chunks, + infoEntities, + communities, + metricDetails, + relationships, + infoLoading, + metricsLoading, }) => { const { breakpoints } = tokens; const isTablet = useMediaQuery(`(min-width:${breakpoints.xs}) and (max-width: ${breakpoints.lg})`); const [activeTab, setActiveTab] = useState( error?.length ? 10 : mode === chatModeLables.global_vector ? 7 : mode === chatModeLables.graph ? 4 : 3 ); - const [infoEntities, setInfoEntities] = useState([]); - const [communities, setCommunities] = useState([]); - const [loading, setLoading] = useState(false); const { userCredentials } = useCredentials(); - const [nodes, setNodes] = useState([]); - const [relationships, setRelationships] = useState([]); - const [chunks, setChunks] = useState([]); const themeUtils = useContext(ThemeWrapperContext); const [, copy] = useCopyToClipboard(); const [copiedText, setcopiedText] = useState(false); @@ -88,7 +96,7 @@ const ChatInfoModal: React.FC = ({ useEffect(() => { if (mode != chatModeLables.graph || error?.trim() !== '') { (async () => { - setLoading(true); + toggleInfoLoading(); try { const response = await chunkEntitiesAPI( userCredentials as UserCredentials, @@ -110,7 +118,7 @@ const ChatInfoModal: React.FC = ({ const communitiesData = response?.data?.data?.community_data; const chunksData = response?.data?.data?.chunk_data; - setInfoEntities( + saveInfoEntitites( nodesData.map((n: Entity) => { if (!n.labels.length && mode === chatModeLables.entity_vector) { return { @@ -121,7 +129,7 @@ const ChatInfoModal: React.FC = ({ return n; }) ); - setNodes( + saveNodes( nodesData.map((n: ExtendedNode) => { if (!n.labels.length && mode === chatModeLables.entity_vector) { return { @@ -132,8 +140,8 @@ const ChatInfoModal: React.FC = ({ return n ?? []; }) ); - setRelationships(relationshipsData ?? []); - setCommunities( + saveChatRelationships(relationshipsData ?? []); + saveCommunities( (communitiesData || []) .map((community: { element_id: string }) => { const communityScore = nodeDetails?.communitydetails?.find( @@ -147,7 +155,7 @@ const ChatInfoModal: React.FC = ({ .sort((a: any, b: any) => b.score - a.score) ); - setChunks( + saveChunks( chunksData .map((chunk: any) => { const chunkScore = nodeDetails?.chunkdetails?.find((c: any) => c.id === chunk.id); @@ -158,13 +166,31 @@ const ChatInfoModal: React.FC = ({ }) .sort((a: any, b: any) => b.score - a.score) ); - setLoading(false); + toggleInfoLoading(); } catch (error) { console.error('Error fetching information:', error); - setLoading(false); + toggleInfoLoading(); } })(); } + (async () => { + try { + toggleMetricsLoading(); + const response = await getChatMetrics(metricquestion, metriccontexts, metricanswer, metricmodel); + toggleMetricsLoading(); + if (response.data.status === 'Success') { + saveMetrics({ ...response.data.data, error: '' }); + } else { + throw new Error(response.data.error); + } + } catch (error) { + if (error instanceof Error) { + toggleMetricsLoading(); + console.log('Error in getting chat metrics', error); + saveMetrics({ error: error.message, faithfulness: 0, answer_relevancy: 0, context_utilization: 0 }); + } + } + })(); () => { setcopiedText(false); }; @@ -185,7 +211,7 @@ const ChatInfoModal: React.FC = ({ Retrieval information - To generate this response, the process took {response_time} seconds,{' '} + To generate this response, the process took {response_time} seconds, utilizing {total_tokens} tokens with the model{' '} {model} in{' '} {mode !== 'vector' ? mode.replace(/\+/g, ' & ') : mode} mode. @@ -197,7 +223,6 @@ const ChatInfoModal: React.FC = ({ ) : ( {mode === chatModeLables.global_vector ? ( - // Only show the Communities tab if mode is global Communities ) : ( <> @@ -217,24 +242,28 @@ const ChatInfoModal: React.FC = ({ <> )} {mode === chatModeLables.entity_vector ? Communities : <>} + Evaluation Metrics )} )} - + + + + - + = ({ {mode === chatModeLables.entity_vector || mode === chatModeLables.global_vector ? ( - + ) : ( <> diff --git a/frontend/src/components/ChatBot/Chatbot.tsx b/frontend/src/components/ChatBot/Chatbot.tsx index e075777db..f085fb696 100644 --- a/frontend/src/components/ChatBot/Chatbot.tsx +++ b/frontend/src/components/ChatBot/Chatbot.tsx @@ -1,4 +1,4 @@ -import React, { FC, lazy, Suspense, useCallback, useEffect, useRef, useState } from 'react'; +import React, { FC, lazy, Suspense, useCallback, useEffect, useReducer, useRef, useState } from 'react'; import { Widget, Typography, @@ -9,10 +9,24 @@ import { useCopyToClipboard, Flex, Box, + TextLink, } from '@neo4j-ndl/react'; -import { XMarkIconOutline } from '@neo4j-ndl/react/icons'; +import { ArrowDownTrayIconOutline, XMarkIconOutline } from '@neo4j-ndl/react/icons'; import ChatBotAvatar from '../../assets/images/chatbot-ai.png'; -import { ChatbotProps, CustomFile, Messages, ResponseMode, UserCredentials, nodeDetailsProps } from '../../types'; +import { + ChatbotProps, + Chunk, + Community, + CustomFile, + Entity, + ExtendedNode, + ExtendedRelationship, + Messages, + MetricsState, + ResponseMode, + UserCredentials, + nodeDetailsProps, +} from '../../types'; import { useCredentials } from '../../context/UserCredentials'; import { chatBotAPI } from '../../services/QnaAPI'; import { v4 as uuidv4 } from 'uuid'; @@ -54,6 +68,19 @@ const Chatbot: FC = (props) => { const [messageError, setmessageError] = useState(''); const [entitiesModal, setEntitiesModal] = useState([]); const [nodeDetailsModal, setNodeDetailsModal] = useState({}); + const [metricQuestion, setMetricQuestion] = useState(''); + const [metricAnswer, setMetricAnswer] = useState(''); + const [metricContext, setMetricContext] = useState(''); + const [nodes, setNodes] = useState([]); + const [relationships, setRelationships] = useState([]); + const [chunks, setChunks] = useState([]); + const [metricDetails, setMetricDetails] = useState(null); + const [infoEntities, setInfoEntities] = useState([]); + const [communities, setCommunities] = useState([]); + const [infoLoading, toggleInfoLoading] = useReducer((s) => !s, false); + const [metricsLoading, toggleMetricsLoading] = useReducer((s) => !s, false); + const downloadLinkRef = useRef(null); + const [activeChat, setActiveChat] = useState(); const [_, copy] = useCopyToClipboard(); const { speak, cancel, speaking } = useSpeechSynthesis({ @@ -70,6 +97,27 @@ const Chatbot: FC = (props) => { setInputMessage(e.target.value); }; + const saveInfoEntitites = (entities: Entity[]) => { + setInfoEntities(entities); + }; + + const saveNodes = (chatNodes: ExtendedNode[]) => { + setNodes(chatNodes); + }; + + const saveChatRelationships = (chatRels: ExtendedRelationship[]) => { + setRelationships(chatRels); + }; + + const saveChunks = (chatChunks: Chunk[]) => { + setChunks(chatChunks); + }; + const saveMetrics = (metricInfo: MetricsState) => { + setMetricDetails(metricInfo); + }; + const saveCommunities = (chatCommunities: Community[]) => { + setCommunities(chatCommunities); + }; useEffect(() => { if (!sessionStorage.getItem('session_id')) { const id = uuidv4(); @@ -173,7 +221,6 @@ const Chatbot: FC = (props) => { const results = await Promise.allSettled(apiCalls); results.forEach((result, index) => { const mode = chatModes[index]; - console.log({ mode }); if (result.status === 'fulfilled') { // @ts-ignore if (result.value.response.data.status === 'Success') { @@ -189,13 +236,16 @@ const Chatbot: FC = (props) => { entities: response.info.entities, nodeDetails: response.info.nodedetails, error: response.info.error, + metric_question: response.info.metric_details.question, + metric_answer: response.info.metric_details.answer, + metric_contexts: response.info.metric_details.contexts, }; if (index === 0) { simulateTypingEffect(chatbotMessageId, responseMode, mode, responseMode.message); } else { setListMessages((prev) => prev.map((msg) => - (msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg) + msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg ) ); } @@ -210,7 +260,7 @@ const Chatbot: FC = (props) => { } else { setListMessages((prev) => prev.map((msg) => - (msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg) + msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg ) ); } @@ -219,7 +269,7 @@ const Chatbot: FC = (props) => { console.error(`API call failed for mode ${mode}:`, result.reason); setListMessages((prev) => prev.map((msg) => - (msg.id === chatbotMessageId + msg.id === chatbotMessageId ? { ...msg, modes: { @@ -227,21 +277,20 @@ const Chatbot: FC = (props) => { [mode]: { message: 'Failed to fetch response for this mode.', error: result.reason }, }, } - : msg) + : msg ) ); } }); - - setListMessages((prev) => { - return prev.map((msg) => (msg.id === chatbotMessageId ? { ...msg, isLoading: false, isTyping: false } : msg)); - }); + setListMessages((prev) => + prev.map((msg) => (msg.id === chatbotMessageId ? { ...msg, isLoading: false, isTyping: false } : msg)) + ); } catch (error) { console.error('Error in handling chat:', error); if (error instanceof Error) { setListMessages((prev) => prev.map((msg) => - (msg.id === chatbotMessageId + msg.id === chatbotMessageId ? { ...msg, isLoading: false, @@ -253,7 +302,7 @@ const Chatbot: FC = (props) => { }, }, } - : msg) + : msg ) ); } @@ -338,6 +387,10 @@ const Chatbot: FC = (props) => { setEntitiesModal(currentMode.entities ?? []); setmessageError(currentMode.error ?? ''); setNodeDetailsModal(currentMode.nodeDetails ?? {}); + setMetricQuestion(currentMode.metric_question ?? ''); + setMetricContext(currentMode.metric_contexts ?? ''); + setMetricAnswer(currentMode.metric_answer ?? ''); + setActiveChat(chat); }, []); const speechHandler = useCallback((chat: Messages) => { @@ -347,6 +400,15 @@ const Chatbot: FC = (props) => { handleSpeak(chat.modes[chat.currentMode]?.message, chat.id); } }, []); + const downloadClickHandler = useCallback(function downloadClickHandler(JsonData: Type) { + const textFile = new Blob([JSON.stringify(JsonData)], { type: 'application/json' }); + if (downloadLinkRef && downloadLinkRef.current) { + downloadLinkRef.current.href = URL.createObjectURL(textFile); + downloadLinkRef.current.download = 'data.json'; + downloadLinkRef.current.click(); + } + }, []); + return (
    @@ -399,7 +461,9 @@ const Chatbot: FC = (props) => { chat.isLoading && index === listMessages.length - 1 && chat.user === 'chatbot' ? 'loader' : '' }`} > - {chat.modes[chat.currentMode]?.message || ''} + + {chat.modes[chat.currentMode]?.message || ''} +
    @@ -509,7 +573,31 @@ const Chatbot: FC = (props) => { onClose={() => setShowInfoModal(false)} open={showInfoModal} > -
    +
    + { + downloadClickHandler({ + chatResponse: activeChat, + chunks, + metricDetails, + communities, + responseTime, + entities: infoEntities, + nodes, + tokensUsed, + model, + }); + }} + > + + + "" + + = (props) => { graphonly_entities={graphEntitites} error={messageError} nodeDetails={nodeDetailsModal} + metricanswer={metricAnswer} + metriccontexts={metricContext} + metricquestion={metricQuestion} + metricmodel={model} + nodes={nodes} + infoEntities={infoEntities} + relationships={relationships} + chunks={chunks} + metricDetails={metricDetails} + communities={communities} + infoLoading={infoLoading} + metricsLoading={metricsLoading} + saveInfoEntitites={saveInfoEntitites} + saveChatRelationships={saveChatRelationships} + saveChunks={saveChunks} + saveCommunities={saveCommunities} + saveMetrics={saveMetrics} + saveNodes={saveNodes} + toggleInfoLoading={toggleInfoLoading} + toggleMetricsLoading={toggleMetricsLoading} /> diff --git a/frontend/src/components/ChatBot/MetricsTab.tsx b/frontend/src/components/ChatBot/MetricsTab.tsx new file mode 100644 index 000000000..a5680b8ad --- /dev/null +++ b/frontend/src/components/ChatBot/MetricsTab.tsx @@ -0,0 +1,113 @@ +import { Banner, DataGrid, DataGridComponents, Typography } from '@neo4j-ndl/react'; +import { MetricsState } from '../../types'; +import { memo, useMemo, useRef } from 'react'; +import { + useReactTable, + getCoreRowModel, + createColumnHelper, + getFilteredRowModel, + getPaginationRowModel, + getSortedRowModel, +} from '@tanstack/react-table'; +import { capitalize } from '../../utils/Utils'; +function MetricsTab({ + metricsLoading, + metricDetails, +}: { + metricsLoading: boolean; + metricDetails: MetricsState | null; +}) { + const columnHelper = createColumnHelper<{ metric: string; score: number }>(); + const tableRef = useRef(null); + + const columns = useMemo( + () => [ + columnHelper.accessor((row) => row.metric, { + id: 'Metric', + cell: (info) => { + const metric = info.getValue(); + const capitilizedMetric = metric.includes('_') + ? metric + .split('_') + .map((w) => capitalize(w)) + .join(' ') + : capitalize(metric); + return ( +
    + {capitilizedMetric} +
    + ); + }, + header: () => Metric, + footer: (info) => info.column.id, + }), + columnHelper.accessor((row) => row.score, { + id: 'Score', + cell: (info) => { + return {info.getValue().toFixed(2)}; + }, + }), + ], + [] + ); + const table = useReactTable({ + data: + metricDetails != null && !metricsLoading + ? Object.entries(metricDetails) + .slice(0, Object.keys(metricDetails).length - 1) + .map(([key, value]) => { + return { metric: key, score: value }; + }) + : [], + columns, + getCoreRowModel: getCoreRowModel(), + getFilteredRowModel: getFilteredRowModel(), + getPaginationRowModel: getPaginationRowModel(), + enableGlobalFilter: false, + autoResetPageIndex: false, + enableRowSelection: true, + enableMultiRowSelection: true, + enableSorting: true, + getSortedRowModel: getSortedRowModel(), + }); + return ( + <> + {metricDetails != null && metricDetails?.error?.trim() != '' ? ( + {metricDetails?.error} + ) : ( + , + PaginationNumericButton: ({ isSelected, innerProps, ...restProps }) => { + return ( + + ); + }, + }} + /> + )} + + ); +} +export default memo(MetricsTab); diff --git a/frontend/src/services/GetRagasMetric.ts b/frontend/src/services/GetRagasMetric.ts new file mode 100644 index 000000000..a72c69e5d --- /dev/null +++ b/frontend/src/services/GetRagasMetric.ts @@ -0,0 +1,17 @@ +import { MetricsResponse } from '../types'; +import api from '../API/Index'; + +export const getChatMetrics = async (question: string, context: string, answer: string, model: string) => { + const formData = new FormData(); + formData.append('question', question); + formData.append('context', `[${context}]`); + formData.append('answer', answer); + formData.append('model', model); + try { + const response = await api.post(`/metric`, formData); + return response; + } catch (error) { + console.log(error); + throw error; + } +}; diff --git a/frontend/src/types.ts b/frontend/src/types.ts index eb0d6c090..283227bcb 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -218,6 +218,9 @@ export type ResponseMode = { graphonly_entities?: []; error?: string; entities?: string[]; + metric_question?: string; + metric_contexts?: string; + metric_answer?: string; }; export interface Messages { id: number; @@ -407,6 +410,14 @@ export interface duplicateNodesData extends Partial { export interface OrphanNodeResponse extends Partial { data: orphanNodeProps[]; } +export type metricdetails = { + faithfulness: number; + answer_relevancy: number; + context_utilization: number; +}; +export interface MetricsResponse extends Omit { + data: metricdetails; +} export interface schema { nodelabels: string[]; relationshipTypes: string[]; @@ -430,6 +441,26 @@ export interface chatInfoMessage extends Partial { error: string; entities_ids: string[]; nodeDetails: nodeDetailsProps; + metricquestion: string; + metricanswer: string; + metriccontexts: string; + metricmodel: string; + nodes: ExtendedNode[]; + relationships: ExtendedRelationship[]; + chunks: Chunk[]; + metricDetails: MetricsState | null; + infoEntities: Entity[]; + communities: Community[]; + infoLoading: boolean; + metricsLoading: boolean; + saveInfoEntitites: (entities: Entity[]) => void; + saveNodes: (chatNodes: ExtendedNode[]) => void; + saveChatRelationships: (chatRels: ExtendedRelationship[]) => void; + saveChunks: (chatChunks: Chunk[]) => void; + saveMetrics: (metricInfo: MetricsState) => void; + saveCommunities: (chatCommunities: Community[]) => void; + toggleInfoLoading: React.DispatchWithoutAction; + toggleMetricsLoading: React.DispatchWithoutAction; } export interface eventResponsetypes extends Omit { @@ -744,3 +775,6 @@ export interface FileContextType { setPostProcessingVal: Dispatch>; } export declare type Side = 'top' | 'right' | 'bottom' | 'left'; +export interface MetricsState extends metricdetails { + error?: string; +} From b8296e94a6516341822fe95a92a1cdb21fc0688b Mon Sep 17 00:00:00 2001 From: aashipandya <156318202+aashipandya@users.noreply.github.com> Date: Thu, 10 Oct 2024 15:58:44 +0530 Subject: [PATCH 159/292] Openai gemini config (#794) * openai and gemini models as config backend * updated dropdown llm values * updated docs --- README.md | 2 -- backend/example.env | 5 +++++ backend/src/llm.py | 14 ++++++++----- backend/src/main.py | 36 ++++++++++++++++++--------------- example.env | 4 ---- frontend/src/utils/Constants.ts | 10 ++++----- 6 files changed, 39 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index f1ef12198..01342a8a4 100644 --- a/README.md +++ b/README.md @@ -127,8 +127,6 @@ Allow unauthenticated request : Yes ## ENV | Env Variable Name | Mandatory/Optional | Default Value | Description | |-------------------------|--------------------|---------------|--------------------------------------------------------------------------------------------------| -| OPENAI_API_KEY | Mandatory | | API key for OpenAI | -| DIFFBOT_API_KEY | Mandatory | | API key for Diffbot | | EMBEDDING_MODEL | Optional | all-MiniLM-L6-v2 | Model for generating the text embedding (all-MiniLM-L6-v2 , openai , vertexai) | | IS_EMBEDDING | Optional | true | Flag to enable text embedding | | KNN_MIN_SCORE | Optional | 0.94 | Minimum score for KNN algorithm | diff --git a/backend/example.env b/backend/example.env index 1d14cfae4..75b817220 100644 --- a/backend/example.env +++ b/backend/example.env @@ -28,6 +28,11 @@ ENTITY_EMBEDDING="" True or False DUPLICATE_SCORE_VALUE = "" DUPLICATE_TEXT_DISTANCE = "" #examples +LLM_MODEL_CONFIG_openai_gpt_3.5="gpt-3.5-turbo-0125,openai_api_key" +LLM_MODEL_CONFIG_openai_gpt_4o_mini="gpt-4o-mini-2024-07-18,openai_api_key" +LLM_MODEL_CONFIG_gemini_1.5_pro="gemini-1.5-pro-002" +LLM_MODEL_CONFIG_gemini_1.5_flash="gemini-1.5-flash-002" +LLM_MODEL_CONFIG_diffbot="diffbot,diffbot_api_key" LLM_MODEL_CONFIG_azure_ai_gpt_35="azure_deployment_name,azure_endpoint or base_url,azure_api_key,api_version" LLM_MODEL_CONFIG_azure_ai_gpt_4o="gpt-4o,https://YOUR-ENDPOINT.openai.azure.com/,azure_api_key,api_version" LLM_MODEL_CONFIG_groq_llama3_70b="model_name,base_url,groq_api_key" diff --git a/backend/src/llm.py b/backend/src/llm.py index c7c6b36e2..f43be2a67 100644 --- a/backend/src/llm.py +++ b/backend/src/llm.py @@ -24,9 +24,11 @@ def get_llm(model: str): env_key = "LLM_MODEL_CONFIG_" + model env_value = os.environ.get(env_key) logging.info("Model: {}".format(env_key)) + if "gemini" in model: + model_name = env_value credentials, project_id = google.auth.default() - model_name = MODEL_VERSIONS[model] + #model_name = MODEL_VERSIONS[model] llm = ChatVertexAI( model_name=model_name, #convert_system_message_to_human=True, @@ -42,9 +44,10 @@ def get_llm(model: str): }, ) elif "openai" in model: - model_name = MODEL_VERSIONS[model] + #model_name = MODEL_VERSIONS[model] + model_name, api_key = env_value.split(",") llm = ChatOpenAI( - api_key=os.environ.get("OPENAI_API_KEY"), + api_key=api_key, model=model_name, temperature=0, ) @@ -93,9 +96,10 @@ def get_llm(model: str): llm = ChatOllama(base_url=base_url, model=model_name) elif "diffbot" in model: - model_name = "diffbot" + #model_name = "diffbot" + model_name, api_key = env_value.split(",") llm = DiffbotGraphTransformer( - diffbot_api_key=os.environ.get("DIFFBOT_API_KEY"), + diffbot_api_key=api_key, extract_types=["entities", "facts"], ) diff --git a/backend/src/main.py b/backend/src/main.py index 8b95b2e88..425a24451 100644 --- a/backend/src/main.py +++ b/backend/src/main.py @@ -518,26 +518,30 @@ def get_chunkId_chunkDoc_list(graph, file_name, pages, retry_condition): else: chunkId_chunkDoc_list=[] chunks = graph.query(QUERY_TO_GET_CHUNKS, params={"filename":file_name}) - for chunk in chunks: - chunk_doc = Document(page_content=chunk['text'], metadata={'id':chunk['id'], 'position':chunk['position']}) - chunkId_chunkDoc_list.append({'chunk_id': chunk['id'], 'chunk_doc': chunk_doc}) - if retry_condition == START_FROM_LAST_PROCESSED_POSITION: - logging.info(f"Retry : start_from_last_processed_position") - starting_chunk = graph.query(QUERY_TO_GET_LAST_PROCESSED_CHUNK_POSITION, params={"filename":file_name}) - if starting_chunk[0]["position"] < len(chunkId_chunkDoc_list): - return len(chunks), chunkId_chunkDoc_list[starting_chunk[0]["position"] - 1:] + if chunks[0]['text'] is None or chunks[0]['text']=="" : + raise Exception(f"Chunks are not created for {file_name}. Please re-upload file and try.") + else: + for chunk in chunks: + chunk_doc = Document(page_content=chunk['text'], metadata={'id':chunk['id'], 'position':chunk['position']}) + chunkId_chunkDoc_list.append({'chunk_id': chunk['id'], 'chunk_doc': chunk_doc}) - elif starting_chunk[0]["position"] == len(chunkId_chunkDoc_list): - starting_chunk = graph.query(QUERY_TO_GET_LAST_PROCESSED_CHUNK_WITHOUT_ENTITY, params={"filename":file_name}) - return len(chunks), chunkId_chunkDoc_list[starting_chunk[0]["position"] - 1:] + if retry_condition == START_FROM_LAST_PROCESSED_POSITION: + logging.info(f"Retry : start_from_last_processed_position") + starting_chunk = graph.query(QUERY_TO_GET_LAST_PROCESSED_CHUNK_POSITION, params={"filename":file_name}) + if starting_chunk[0]["position"] < len(chunkId_chunkDoc_list): + return len(chunks), chunkId_chunkDoc_list[starting_chunk[0]["position"] - 1:] + + elif starting_chunk[0]["position"] == len(chunkId_chunkDoc_list): + starting_chunk = graph.query(QUERY_TO_GET_LAST_PROCESSED_CHUNK_WITHOUT_ENTITY, params={"filename":file_name}) + return len(chunks), chunkId_chunkDoc_list[starting_chunk[0]["position"] - 1:] + + else: + raise Exception(f"All chunks of {file_name} are alreday processed. If you want to re-process, Please start from begnning") else: - raise Exception(f"All chunks of {file_name} are alreday processed. If you want to re-process, Please start from begnning") - - else: - logging.info(f"Retry : start_from_beginning with chunks {len(chunkId_chunkDoc_list)}") - return len(chunks), chunkId_chunkDoc_list + logging.info(f"Retry : start_from_beginning with chunks {len(chunkId_chunkDoc_list)}") + return len(chunks), chunkId_chunkDoc_list def get_source_list_from_graph(uri,userName,password,db_name=None): """ diff --git a/example.env b/example.env index 23bcc6e06..227c51904 100644 --- a/example.env +++ b/example.env @@ -1,7 +1,3 @@ -# Mandatory -OPENAI_API_KEY="" -DIFFBOT_API_KEY="" - # Optional Backend EMBEDDING_MODEL="all-MiniLM-L6-v2" IS_EMBEDDING="true" diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index f740531d0..47a19e701 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -41,11 +41,11 @@ export const llms = ? (process.env.VITE_LLM_MODELS?.split(',') as string[]) : [ 'diffbot', - 'openai-gpt-3.5', - 'openai-gpt-4o', - 'openai-gpt-4o-mini', - 'gemini-1.5-pro', - 'gemini-1.5-flash', + 'openai_gpt_3.5', + 'openai_gpt_4o', + 'openai_gpt_4o_mini', + 'gemini_1.5_pro', + 'gemini_1.5_flash', 'azure_ai_gpt_35', 'azure_ai_gpt_4o', 'ollama_llama3', From b04f3828da4d8f099676389474e1c5eb99078882 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Thu, 10 Oct 2024 10:52:37 +0000 Subject: [PATCH 160/292] Added the user action for metrics table --- .../src/components/ChatBot/ChatInfoModal.tsx | 53 ++++++++++++------- frontend/src/components/ChatBot/Chatbot.tsx | 12 ++--- .../src/components/ChatBot/MetricsTab.tsx | 6 +-- 3 files changed, 43 insertions(+), 28 deletions(-) diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index 199d9eb6d..c666d5206 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -8,6 +8,7 @@ import { useCopyToClipboard, Banner, useMediaQuery, + Button, } from '@neo4j-ndl/react'; import { DocumentDuplicateIconOutline, ClipboardDocumentCheckIconOutline } from '@neo4j-ndl/react/icons'; import '../../styling/info.css'; @@ -27,6 +28,7 @@ import { chatModeLables } from '../../utils/Constants'; import { Relationship } from '@neo4j-nvl/base'; import { getChatMetrics } from '../../services/GetRagasMetric'; import MetricsTab from './MetricsTab'; +import { Stack } from '@mui/material'; const ChatInfoModal: React.FC = ({ sources, @@ -69,6 +71,7 @@ const ChatInfoModal: React.FC = ({ const themeUtils = useContext(ThemeWrapperContext); const [, copy] = useCopyToClipboard(); const [copiedText, setcopiedText] = useState(false); + const [showMetricsTable, setShowMetricsTable] = useState(false); const actions: CypherCodeBlockProps['actions'] = useMemo( () => [ @@ -173,32 +176,34 @@ const ChatInfoModal: React.FC = ({ } })(); } - (async () => { - try { - toggleMetricsLoading(); - const response = await getChatMetrics(metricquestion, metriccontexts, metricanswer, metricmodel); - toggleMetricsLoading(); - if (response.data.status === 'Success') { - saveMetrics({ ...response.data.data, error: '' }); - } else { - throw new Error(response.data.error); - } - } catch (error) { - if (error instanceof Error) { - toggleMetricsLoading(); - console.log('Error in getting chat metrics', error); - saveMetrics({ error: error.message, faithfulness: 0, answer_relevancy: 0, context_utilization: 0 }); - } - } - })(); () => { setcopiedText(false); + setShowMetricsTable(false); }; }, [nodeDetails, mode, error]); const onChangeTabs = (tabId: number) => { setActiveTab(tabId); }; + const loadMetrics = async () => { + setShowMetricsTable(true); + try { + toggleMetricsLoading(); + const response = await getChatMetrics(metricquestion, metriccontexts, metricanswer, metricmodel); + toggleMetricsLoading(); + if (response.data.status === 'Success') { + saveMetrics({ ...response.data.data, error: '' }); + } else { + throw new Error(response.data.error); + } + } catch (error) { + if (error instanceof Error) { + toggleMetricsLoading(); + console.log('Error in getting chat metrics', error); + saveMetrics({ error: error.message, faithfulness: 0, answer_relevancy: 0, context_utilization: 0 }); + } + } + }; return ( @@ -252,7 +257,17 @@ const ChatInfoModal: React.FC = ({ - + + + We use several key metrics to assess the quality of our chat responses. Click the button below to view + detailed scores for this interaction. These scores help us continuously improve the accuracy and + helpfulness of our chatbots. + + {showMetricsTable && } + + = (props) => { } else { setListMessages((prev) => prev.map((msg) => - msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg + (msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg) ) ); } @@ -260,7 +260,7 @@ const Chatbot: FC = (props) => { } else { setListMessages((prev) => prev.map((msg) => - msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg + (msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg) ) ); } @@ -269,7 +269,7 @@ const Chatbot: FC = (props) => { console.error(`API call failed for mode ${mode}:`, result.reason); setListMessages((prev) => prev.map((msg) => - msg.id === chatbotMessageId + (msg.id === chatbotMessageId ? { ...msg, modes: { @@ -277,7 +277,7 @@ const Chatbot: FC = (props) => { [mode]: { message: 'Failed to fetch response for this mode.', error: result.reason }, }, } - : msg + : msg) ) ); } @@ -290,7 +290,7 @@ const Chatbot: FC = (props) => { if (error instanceof Error) { setListMessages((prev) => prev.map((msg) => - msg.id === chatbotMessageId + (msg.id === chatbotMessageId ? { ...msg, isLoading: false, @@ -302,7 +302,7 @@ const Chatbot: FC = (props) => { }, }, } - : msg + : msg) ) ); } diff --git a/frontend/src/components/ChatBot/MetricsTab.tsx b/frontend/src/components/ChatBot/MetricsTab.tsx index a5680b8ad..17b5e67ae 100644 --- a/frontend/src/components/ChatBot/MetricsTab.tsx +++ b/frontend/src/components/ChatBot/MetricsTab.tsx @@ -1,4 +1,4 @@ -import { Banner, DataGrid, DataGridComponents, Typography } from '@neo4j-ndl/react'; +import { Banner, Box, DataGrid, DataGridComponents, Typography } from '@neo4j-ndl/react'; import { MetricsState } from '../../types'; import { memo, useMemo, useRef } from 'react'; import { @@ -71,7 +71,7 @@ function MetricsTab({ getSortedRowModel: getSortedRowModel(), }); return ( - <> + {metricDetails != null && metricDetails?.error?.trim() != '' ? ( {metricDetails?.error} ) : ( @@ -107,7 +107,7 @@ function MetricsTab({ }} /> )} - + ); } export default memo(MetricsTab); From f97806c4375ca81e2f1c5cce8204772472aee9ca Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Thu, 10 Oct 2024 18:05:12 +0530 Subject: [PATCH 161/292] Graph enhancements (#795) * graph changes * graph properties changes * graph communities changes * graph type selection * checkbox check changes --- .../components/Graph/CheckboxSelection.tsx | 4 +- .../components/Graph/GraphPropertiesPanel.tsx | 91 +++++ .../components/Graph/GraphPropertiesTable.tsx | 39 +++ .../src/components/Graph/GraphViewModal.tsx | 322 +++++------------- frontend/src/components/Graph/LegendsChip.tsx | 2 +- frontend/src/components/Graph/ResizePanel.tsx | 56 +++ .../src/components/Graph/ResultOverview.tsx | 197 +++++++++++ frontend/src/types.ts | 55 ++- frontend/src/utils/Constants.ts | 233 ++++++------- frontend/src/utils/Utils.ts | 53 +-- 10 files changed, 646 insertions(+), 406 deletions(-) create mode 100644 frontend/src/components/Graph/GraphPropertiesPanel.tsx create mode 100644 frontend/src/components/Graph/GraphPropertiesTable.tsx create mode 100644 frontend/src/components/Graph/ResizePanel.tsx create mode 100644 frontend/src/components/Graph/ResultOverview.tsx diff --git a/frontend/src/components/Graph/CheckboxSelection.tsx b/frontend/src/components/Graph/CheckboxSelection.tsx index d0a3429f2..b8caf7484 100644 --- a/frontend/src/components/Graph/CheckboxSelection.tsx +++ b/frontend/src/components/Graph/CheckboxSelection.tsx @@ -7,7 +7,7 @@ const CheckboxSelection: React.FC = ({ graphType, loading, handleChange, - isgds, + isCommunity, isDocChunk, isEntity, }) => ( @@ -29,7 +29,7 @@ const CheckboxSelection: React.FC = ({ onChange={() => handleChange('Entities')} /> )} - {isgds && ( + {isCommunity && ( a.toLowerCase().localeCompare(b.toLowerCase()); + +const isNode = (item: BasicNode | BasicRelationship): item is BasicNode => { + return 'labels' in item && !('from' in item) && !('to' in item); +}; + +const GraphPropertiesPanel = ({ inspectedItem, newScheme }: GraphPropertiesPanelProps) => { + const inspectedItemType = isNode(inspectedItem) ? 'node' : 'relationship'; + const properties = inspectedItemType === 'node' + ? [ + { + key: '', + value: `${(inspectedItem as BasicNode).id}`, + type: 'String', + }, + ...Object.keys((inspectedItem as BasicNode).properties).map((key) => { + const value = (inspectedItem as BasicNode).properties[key]; + return { key: key, value: value ?? '' }; + }), + ] + : [ + { + key: '', + value: `${(inspectedItem as BasicRelationship).id}`, + type: 'String', + }, + { + key: '', + value: `${(inspectedItem as BasicRelationship).from}`, + type: 'String', + }, + { + key: '', + value: `${(inspectedItem as BasicRelationship).to}`, + type: 'String', + }, + { + key: '', + value: `${(inspectedItem as BasicRelationship).caption ?? ''}`, + type: 'String', + }, + ]; + const labelsSorted = useMemo(() => { + if (isNode(inspectedItem)) { + return [...inspectedItem.labels].sort(sortAlphabetically); + } + return []; + }, [inspectedItem]); + + return ( + <> + +
    + {inspectedItemType === 'node' ? 'Node details' : 'Relationship details'} +
    +
    + +
    + {isNode(inspectedItem) ? ( + labelsSorted.map((label) => ( + + )) + ) : ( + + )} +
    +
    + + + + ); +} + +export default GraphPropertiesPanel; \ No newline at end of file diff --git a/frontend/src/components/Graph/GraphPropertiesTable.tsx b/frontend/src/components/Graph/GraphPropertiesTable.tsx new file mode 100644 index 000000000..8cd7571c7 --- /dev/null +++ b/frontend/src/components/Graph/GraphPropertiesTable.tsx @@ -0,0 +1,39 @@ +import { GraphLabel, Typography } from '@neo4j-ndl/react'; +import { GraphPropertiesTableProps } from '../../types'; + +const GraphPropertiesTable = ({ propertiesWithTypes }: GraphPropertiesTableProps): JSX.Element => { + console.log('props', propertiesWithTypes); + return ( +
    +
    + + Key + + Value +
    + {propertiesWithTypes.map(({ key, value }, _) => { + return ( +
    +
    + + {key} + +
    +
    + {value} +
    +
    + ); + })} +
    + ); +}; + +export default GraphPropertiesTable; \ No newline at end of file diff --git a/frontend/src/components/Graph/GraphViewModal.tsx b/frontend/src/components/Graph/GraphViewModal.tsx index 9dc561553..cb995a014 100644 --- a/frontend/src/components/Graph/GraphViewModal.tsx +++ b/frontend/src/components/Graph/GraphViewModal.tsx @@ -2,15 +2,15 @@ import { Banner, Dialog, Flex, - IconButton, IconButtonArray, LoadingSpinner, - TextInput, - Typography, useDebounce, } from '@neo4j-ndl/react'; -import { useCallback, useEffect, useRef, useState } from 'react'; +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { + BasicNode, + BasicRelationship, + EntityType, ExtendedNode, ExtendedRelationship, GraphType, @@ -21,30 +21,29 @@ import { import { InteractiveNvlWrapper } from '@neo4j-nvl/react'; import NVL from '@neo4j-nvl/base'; import type { Node, Relationship } from '@neo4j-nvl/base'; -import { Resizable } from 're-resizable'; import { ArrowPathIconOutline, - DragIcon, FitToScreenIcon, - MagnifyingGlassIconOutline, MagnifyingGlassMinusIconOutline, MagnifyingGlassPlusIconOutline, } from '@neo4j-ndl/react/icons'; import { IconButtonWithToolTip } from '../UI/IconButtonToolTip'; -import { filterData, getCheckboxConditions, processGraphData, sortAlphabetically } from '../../utils/Utils'; +import { filterData, getCheckboxConditions, graphTypeFromNodes, processGraphData } from '../../utils/Utils'; import { useCredentials } from '../../context/UserCredentials'; -import { LegendsChip } from './LegendsChip'; + import graphQueryAPI from '../../services/GraphQuery'; import { graphLabels, intitalGraphType, - mouseEventCallbacks, nvlOptions, queryMap, - RESULT_STEP_SIZE, } from '../../utils/Constants'; import CheckboxSelection from './CheckboxSelection'; -import { ShowAll } from '../UI/ShowAll'; + +import ResultOverview from './ResultOverview'; +import { ResizePanelDetails } from './ResizePanel'; +import GraphPropertiesPanel from './GraphPropertiesPanel'; + const GraphViewModal: React.FunctionComponent = ({ open, @@ -57,51 +56,29 @@ const GraphViewModal: React.FunctionComponent = ({ }) => { const nvlRef = useRef(null); const [nodes, setNodes] = useState([]); - const [relationships, setRelationships] = useState([]); + const [relationships, setRelationships] = useState([]); const [allNodes, setAllNodes] = useState([]); const [allRelationships, setAllRelationships] = useState([]); const [loading, setLoading] = useState(false); const [status, setStatus] = useState<'unknown' | 'success' | 'danger'>('unknown'); const [statusMessage, setStatusMessage] = useState(''); - const { userCredentials, isGdsActive } = useCredentials(); + const { userCredentials } = useCredentials(); const [scheme, setScheme] = useState({}); const [newScheme, setNewScheme] = useState({}); const [searchQuery, setSearchQuery] = useState(''); const debouncedQuery = useDebounce(searchQuery, 300); - const [graphType, setGraphType] = useState(intitalGraphType(isGdsActive)); + const [graphType, setGraphType] = useState([]); const [disableRefresh, setDisableRefresh] = useState(false); - - // the checkbox selection - const handleCheckboxChange = (graph: GraphType) => { - const currentIndex = graphType.indexOf(graph); - const newGraphSelected = [...graphType]; - if (currentIndex === -1) { - newGraphSelected.push(graph); - initGraph(newGraphSelected, allNodes, allRelationships, scheme); - } else { - newGraphSelected.splice(currentIndex, 1); - initGraph(newGraphSelected, allNodes, allRelationships, scheme); - } - setSearchQuery(''); - setGraphType(newGraphSelected); - }; - - const nodeCount = (nodes: ExtendedNode[], label: string): number => { - return [...new Set(nodes?.filter((n) => n.labels?.includes(label)).map((i) => i.id))].length; - }; - - const relationshipCount = (relationships: ExtendedRelationship[], label: string): number => { - return [...new Set(relationships?.filter((r) => r.caption?.includes(label)).map((i) => i.id))].length; - }; + const [selected, setSelected] = useState<{ type: EntityType; id: string } | undefined>(undefined); const graphQuery: string = graphType.includes('DocumentChunk') && graphType.includes('Entities') ? queryMap.DocChunkEntities : graphType.includes('DocumentChunk') - ? queryMap.DocChunks - : graphType.includes('Entities') - ? queryMap.Entities - : ''; + ? queryMap.DocChunks + : graphType.includes('Entities') + ? queryMap.Entities + : ''; // fit graph to original position const handleZoomToFit = () => { @@ -110,7 +87,7 @@ const GraphViewModal: React.FunctionComponent = ({ {} ); }; - +console.log('graphType', graphType); // Unmounting the component useEffect(() => { const timeoutId = setTimeout(() => { @@ -120,7 +97,7 @@ const GraphViewModal: React.FunctionComponent = ({ if (nvlRef.current) { nvlRef.current?.destroy(); } - setGraphType(intitalGraphType(isGdsActive)); + setGraphType([]); clearTimeout(timeoutId); setScheme({}); setNodes([]); @@ -128,18 +105,26 @@ const GraphViewModal: React.FunctionComponent = ({ setAllNodes([]); setAllRelationships([]); setSearchQuery(''); + setSelected(undefined); }; }, []); + useEffect(() => { + const updateGraphType = graphTypeFromNodes(allNodes); + if (Array.isArray(updateGraphType)) { + setGraphType(updateGraphType); + } + }, [allNodes]) + const fetchData = useCallback(async () => { try { const nodeRelationshipData = viewPoint === graphLabels.showGraphView ? await graphQueryAPI( - userCredentials as UserCredentials, - graphQuery, - selectedRows?.map((f) => f.name) - ) + userCredentials as UserCredentials, + graphQuery, + selectedRows?.map((f) => f.name) + ) : await graphQueryAPI(userCredentials as UserCredentials, graphQuery, [inspectedName ?? '']); return nodeRelationshipData; } catch (error: any) { @@ -188,7 +173,7 @@ const GraphViewModal: React.FunctionComponent = ({ useEffect(() => { if (open) { setLoading(true); - setGraphType(intitalGraphType(isGdsActive)); + setGraphType([]); if (viewPoint !== 'chatInfoView') { graphApi(); } else { @@ -202,7 +187,7 @@ const GraphViewModal: React.FunctionComponent = ({ setLoading(false); } } - }, [open, isGdsActive]); + }, [open]); useEffect(() => { handleSearch(debouncedQuery); @@ -220,7 +205,6 @@ const GraphViewModal: React.FunctionComponent = ({ finalNodes ?? [], finalRels ?? [], schemeVal, - isGdsActive ); setNodes(filteredNodes); setRelationships(filteredRelations); @@ -228,6 +212,17 @@ const GraphViewModal: React.FunctionComponent = ({ } }; + + const selectedItem = useMemo(() => { + if (selected === undefined) { + return undefined; + } + if (selected.type === 'node') { + return nodes.find((node) => node.id === selected.id); + } + return relationships.find((relationship) => relationship.id === selected.id); + }, [selected, relationships, nodes]); + // The search and update nodes const handleSearch = useCallback( (value: string) => { @@ -236,7 +231,6 @@ const GraphViewModal: React.FunctionComponent = ({ if (query === '') { return { ...node, - activated: false, selected: false, size: graphLabels.nodeSize, }; @@ -246,21 +240,19 @@ const GraphViewModal: React.FunctionComponent = ({ const match = id.toLowerCase().includes(query) || propertiesMatch || caption?.toLowerCase().includes(query); return { ...node, - activated: match, selected: match, size: match && viewPoint === graphLabels.showGraphView ? 100 : match && viewPoint !== graphLabels.showGraphView - ? 50 - : graphLabels.nodeSize, + ? 50 + : graphLabels.nodeSize, }; }); // deactivating any active relationships const updatedRelationships = relationships.map((rel) => { return { ...rel, - activated: false, selected: false, }; }); @@ -282,6 +274,26 @@ const GraphViewModal: React.FunctionComponent = ({ const checkBoxView = viewPoint !== graphLabels.chatInfoView; + // the checkbox selection + const handleCheckboxChange = (graph: GraphType) => { + const currentIndex = graphType.indexOf(graph); + const newGraphSelected = [...graphType]; + if (currentIndex === -1) { + newGraphSelected.push(graph); + initGraph(newGraphSelected, allNodes, allRelationships, scheme); + } else { + newGraphSelected.splice(currentIndex, 1); + initGraph(newGraphSelected, allNodes, allRelationships, scheme); + } + setSearchQuery(''); + setGraphType(newGraphSelected); + setSelected(undefined); + if (nvlRef.current && nvlRef?.current?.getScale() > 1) { + handleZoomToFit(); + } + }; + + //Callback const nvlCallbacks = { onLayoutComputing(isComputing: boolean) { if (!isComputing) { @@ -316,96 +328,31 @@ const GraphViewModal: React.FunctionComponent = ({ setStatusMessage(''); setGraphViewOpen(false); setScheme({}); - setGraphType(intitalGraphType(isGdsActive)); + setGraphType([]); setNodes([]); setRelationships([]); setAllNodes([]); setAllRelationships([]); setSearchQuery(''); + setSelected(undefined); }; - // sort the legends in with Chunk and Document always the first two values - const nodeCheck = Object.keys(newScheme).sort((a, b) => { - if (a === graphLabels.document || a === graphLabels.chunk) { - return -1; - } else if (b === graphLabels.document || b === graphLabels.chunk) { - return 1; - } - return a.localeCompare(b); - }); - // get sorted relationships - const relationshipsSorted = relationships.sort(sortAlphabetically); - - // To get the relationship count - const groupedAndSortedRelationships: ExtendedRelationship[] = Object.values( - relationshipsSorted.reduce((acc: { [key: string]: ExtendedRelationship }, relType: Relationship) => { - const key = relType.caption || ''; - if (!acc[key]) { - acc[key] = { ...relType, count: 0 }; - } - - acc[key]!.count += relationshipCount(relationships as ExtendedRelationship[], key); - return acc; - }, {}) - ); - - // On Node Click, highlighting the nodes and deactivating any active relationships - const handleNodeClick = (nodeLabel: string) => { - const updatedNodes = nodes.map((node) => { - const isActive = node.labels.includes(nodeLabel); - return { - ...node, - activated: isActive, - selected: isActive, - size: - isActive && viewPoint === graphLabels.showGraphView - ? 100 - : isActive && viewPoint !== graphLabels.showGraphView - ? 50 - : graphLabels.nodeSize, - }; - }); - // deactivating any active relationships - const updatedRelationships = relationships.map((rel) => { - return { - ...rel, - activated: false, - selected: false, - }; - }); - if (searchQuery !== '') { - setSearchQuery(''); - } - setNodes(updatedNodes); - setRelationships(updatedRelationships); - }; - // On Relationship Legend Click, highlight the relationships and deactivating any active nodes - const handleRelationshipClick = (nodeLabel: string) => { - const updatedRelations = relationships.map((rel) => { - return { - ...rel, - activated: rel?.caption?.includes(nodeLabel), - selected: rel?.caption?.includes(nodeLabel), - }; - }); - // // deactivating any active nodes - const updatedNodes = nodes.map((node) => { - return { - ...node, - activated: false, - selected: false, - size: graphLabels.nodeSize, - }; - }); - if (searchQuery !== '') { - setSearchQuery(''); - } - setRelationships(updatedRelations); - setNodes(updatedNodes); + const mouseEventCallbacks = { + onNodeClick: (clickedNode: Node) => { + setSelected({ type: 'node', id: clickedNode.id }); + }, + onRelationshipClick: (clickedRelationship: Relationship) => { + setSelected({ type: 'relationship', id: clickedRelationship.id }); + }, + onCanvasClick: () => { + setSelected(undefined); + }, + onPan: true, + onZoom: true, + onDrag: true, }; - // const isCommunity = allNodes.some(n=>n.labels.includes('__Community__')); return ( <> = ({
    - }} - handleClasses={{ left: 'ml-1' }} - > -
    - {nodeCheck.length > 0 && ( - <> - - {graphLabels.resultOverview} -
    - { - setSearchQuery(e.target.value); - }} - placeholder='Search On Node Properties' - fluid={true} - leftIcon={ - - - - } - /> -
    - - {graphLabels.totalNodes} ({nodes.length}) - -
    -
    - - {nodeCheck.map((nodeLabel, index) => ( - handleNodeClick(nodeLabel)} - /> - ))} - -
    - - )} - {relationshipsSorted.length > 0 && ( - <> - - - {graphLabels.totalRelationships} ({relationships.length}) - - -
    - - {groupedAndSortedRelationships.map((relType, index) => ( - handleRelationshipClick(relType.caption || '')} - /> - ))} - -
    - - )} -
    -
    + + {selectedItem !== undefined ? ( + + ) : ( + )} +
    )} diff --git a/frontend/src/components/Graph/LegendsChip.tsx b/frontend/src/components/Graph/LegendsChip.tsx index 832150fad..1196d8554 100644 --- a/frontend/src/components/Graph/LegendsChip.tsx +++ b/frontend/src/components/Graph/LegendsChip.tsx @@ -6,7 +6,7 @@ export const LegendsChip: React.FunctionComponent = ({ scheme, return ( { + if (!open) { + return null; + } + return ( + }} + handleClasses={{ left: 'ml-1' }} + onResizeStop={onResizeStop} + > +
    + {children} +
    +
    + ); +} +const Title = ({ children }: { children: React.ReactNode }) => { + return ( +
    + {children} +
    + ); +} +ResizePanelDetails.Title = Title; + +const Content = ({ children }: { children: React.ReactNode }) => { + return
    {children}
    ; +} +ResizePanelDetails.Content = Content; \ No newline at end of file diff --git a/frontend/src/components/Graph/ResultOverview.tsx b/frontend/src/components/Graph/ResultOverview.tsx new file mode 100644 index 000000000..1f755d188 --- /dev/null +++ b/frontend/src/components/Graph/ResultOverview.tsx @@ -0,0 +1,197 @@ + +import { Flex, IconButton, TextInput, Typography } from '@neo4j-ndl/react'; +import { MagnifyingGlassIconOutline } from "@neo4j-ndl/react/icons"; +import { LegendsChip } from './LegendsChip'; +import { + ExtendedNode, + ExtendedRelationship, + Scheme, +} from '../../types'; +import { + graphLabels, + RESULT_STEP_SIZE, +} from '../../utils/Constants'; +import type { Relationship } from '@neo4j-nvl/base'; +import { ShowAll } from '../UI/ShowAll'; +import { sortAlphabetically } from "../../utils/Utils"; +import { Dispatch, SetStateAction } from "react"; + +interface OverViewProps { + nodes: ExtendedNode[]; + relationships: ExtendedRelationship[]; + newScheme: Scheme; + searchQuery: string + setSearchQuery: Dispatch> + viewPoint: string, + setNodes: Dispatch>, + setRelationships: Dispatch> +} +const ResultOverview: React.FunctionComponent = ({ nodes, relationships, newScheme, searchQuery, setSearchQuery, viewPoint, setNodes, setRelationships }) => { + const nodeCount = (nodes: ExtendedNode[], label: string): number => { + return [...new Set(nodes?.filter((n) => n.labels?.includes(label)).map((i) => i.id))].length; + }; + + // sort the legends in with Chunk and Document always the first two values + const nodeCheck = Object.keys(newScheme).sort((a, b) => { + if (a === graphLabels.document || a === graphLabels.chunk) { + return -1; + } else if (b === graphLabels.document || b === graphLabels.chunk) { + return 1; + } + return a.localeCompare(b); + }); + + // get sorted relationships + const relationshipsSorted = relationships.sort(sortAlphabetically); + + + const relationshipCount = (relationships: ExtendedRelationship[], label: string): number => { + return [...new Set(relationships?.filter((r) => r.caption?.includes(label)).map((i) => i.id))].length; + }; + + // To get the relationship count + const groupedAndSortedRelationships: ExtendedRelationship[] = Object.values( + relationshipsSorted.reduce((acc: { [key: string]: ExtendedRelationship }, relType: Relationship) => { + const key = relType.caption || ''; + if (!acc[key]) { + acc[key] = { ...relType, count: 0 }; + } + (acc[key] as { count: number }).count += relationshipCount(relationships as ExtendedRelationship[], key); + return acc; + }, {}) + ); + + // On Relationship Legend Click, highlight the relationships and deactivating any active nodes + const handleRelationshipClick = (nodeLabel: string) => { + const updatedRelations = relationships.map((rel) => { + return { + ...rel, + selected: rel?.caption?.includes(nodeLabel), + }; + }); + + // // deactivating any active nodes + const updatedNodes = nodes.map((node) => { + return { + ...node, + selected: false, + size: graphLabels.nodeSize, + }; + }); + if (searchQuery !== '') { + setSearchQuery(''); + } + setRelationships(updatedRelations); + setNodes(updatedNodes); + }; + + + + // On Node Click, highlighting the nodes and deactivating any active relationships + const handleNodeClick = (nodeLabel: string) => { + const updatedNodes = nodes.map((node) => { + const isActive = node.labels.includes(nodeLabel); + return { + ...node, + selected: isActive, + size: + isActive && viewPoint === graphLabels.showGraphView + ? 100 + : isActive && viewPoint !== graphLabels.showGraphView + ? 50 + : graphLabels.nodeSize, + }; + }); + // deactivating any active relationships + const updatedRelationships = relationships.map((rel) => { + return { + ...rel, + selected: false, + }; + }); + if (searchQuery !== '') { + setSearchQuery(''); + } + setNodes(updatedNodes); + setRelationships(updatedRelationships); + }; + + return ( + <> + {nodeCheck.length > 0 && ( + <> + + {graphLabels.resultOverview} +
    + { + setSearchQuery(e.target.value); + }} + placeholder='Search On Node Properties' + fluid={true} + leftIcon={ + + + + } + /> +
    + + {graphLabels.totalNodes} ({nodes.length}) + +
    +
    + + {nodeCheck.map((nodeLabel, index) => ( + handleNodeClick(nodeLabel)} + /> + ))} + +
    + + )} + {relationshipsSorted.length > 0 && ( + <> + + + {graphLabels.totalRelationships} ({relationships.length}) + + +
    + + {groupedAndSortedRelationships.map((relType, index) => ( + handleRelationshipClick(relType.caption || '')} + scheme={{}} /> + ))} + +
    + + )} + + ) +} + +export default ResultOverview; \ No newline at end of file diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 283227bcb..392754d77 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -244,7 +244,7 @@ export type ChatbotProps = { isFullScreen?: boolean; connectionStatus: boolean; }; -export interface WikipediaModalTypes extends Omit {} +export interface WikipediaModalTypes extends Omit { } export interface GraphViewModalProps { open: boolean; @@ -266,7 +266,7 @@ export interface CheckboxSectionProps { graphType: GraphType[]; loading: boolean; handleChange: (graph: GraphType) => void; - isgds: boolean; + isCommunity: boolean; isDocChunk: boolean; isEntity: boolean; } @@ -347,8 +347,8 @@ export interface LegendChipProps { scheme: Scheme; label: string; type: 'node' | 'relationship' | 'propertyKey'; - count: number; - onClick: (e: React.MouseEvent) => void; + count?: number; + onClick?: (e: React.MouseEvent) => void; } export interface FileContextProviderProps { children: ReactNode; @@ -430,6 +430,10 @@ export interface SourceListServerData { message?: string; } +export interface MetricsState extends metricdetails { + error?: string; +} + export interface chatInfoMessage extends Partial { sources: string[]; model: string; @@ -590,13 +594,6 @@ export interface Origin { horizontal: Horizontal; } -export type BasicNode = { - id: string; - labels: string[]; - properties: Record; - propertyTypes: Record; -}; - export type GraphStatsLabels = Record< string, { @@ -614,7 +611,7 @@ export interface ExtendedNode extends Node { } export interface ExtendedRelationship extends Relationship { - count: number; + count?: number; } export interface connectionState { openPopUp: boolean; @@ -775,6 +772,34 @@ export interface FileContextType { setPostProcessingVal: Dispatch>; } export declare type Side = 'top' | 'right' | 'bottom' | 'left'; -export interface MetricsState extends metricdetails { - error?: string; -} + +export type EntityType = 'node' | 'relationship'; + +export type BasicRelationship = { + id: string; + to: string; + from: string; + type: string; + caption: string; +}; + +export type BasicNode = { + id: string; + type: string; + labels: string[]; + properties: Record; + propertyTypes: Record; +}; + + +export type GraphPropertiesTableProps = { + propertiesWithTypes: { + key: string; + value: string; + }[]; +}; + +export type GraphPropertiesPanelProps = { + inspectedItem: BasicNode | BasicRelationship; + newScheme: Scheme; +}; diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index 47a19e701..34e1b7263 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -3,34 +3,6 @@ import { GraphType, OptionType } from '../types'; import { getDateTime, getDescriptionForChatMode } from './Utils'; import chatbotmessages from '../assets/ChatbotMessages.json'; -export const document = `+ [docs]`; - -export const chunks = `+ collect { MATCH p=(c)-[:NEXT_CHUNK]-() RETURN p } // chunk-chain -+ collect { MATCH p=(c)-[:SIMILAR]-() RETURN p } // similar-chunks`; - -export const entities = `+ collect { OPTIONAL MATCH (c:Chunk)-[:HAS_ENTITY]->(e), p=(e)-[*0..1]-(:!Chunk) RETURN p}`; - -export const docEntities = `+ [docs] -+ collect { MATCH (c:Chunk)-[:HAS_ENTITY]->(e), p=(e)--(:!Chunk) RETURN p }`; - -export const docChunks = `+[chunks] -+collect {MATCH p=(c)-[:FIRST_CHUNK]-() RETURN p} //first chunk -+ collect { MATCH p=(c)-[:NEXT_CHUNK]-() RETURN p } // chunk-chain -+ collect { MATCH p=(c)-[:SIMILAR]-() RETURN p } // similar-chunk`; - -export const chunksEntities = `+ collect { MATCH p=(c)-[:NEXT_CHUNK]-() RETURN p } // chunk-chain - -+ collect { MATCH p=(c)-[:SIMILAR]-() RETURN p } // similar-chunks -//chunks with entities -+ collect { OPTIONAL MATCH p=(c:Chunk)-[:HAS_ENTITY]->(e)-[*0..1]-(:!Chunk) RETURN p }`; - -export const docChunkEntities = `+[chunks] -+collect {MATCH p=(c)-[:FIRST_CHUNK]-() RETURN p} //first chunk -+ collect { MATCH p=(c)-[:NEXT_CHUNK]-() RETURN p } // chunk-chain -+ collect { MATCH p=(c)-[:SIMILAR]-() RETURN p } // similar-chunks -//chunks with entities -+ collect { OPTIONAL MATCH p=(c:Chunk)-[:HAS_ENTITY]->(e)-[*0..1]-(:!Chunk) RETURN p }`; - export const APP_SOURCES = process.env.VITE_REACT_APP_SOURCES !== '' ? (process.env.VITE_REACT_APP_SOURCES?.split(',') as string[]) @@ -40,26 +12,26 @@ export const llms = process.env?.VITE_LLM_MODELS?.trim() != '' ? (process.env.VITE_LLM_MODELS?.split(',') as string[]) : [ - 'diffbot', - 'openai_gpt_3.5', - 'openai_gpt_4o', - 'openai_gpt_4o_mini', - 'gemini_1.5_pro', - 'gemini_1.5_flash', - 'azure_ai_gpt_35', - 'azure_ai_gpt_4o', - 'ollama_llama3', - 'groq_llama3_70b', - 'anthropic_claude_3_5_sonnet', - 'fireworks_llama_v3p2_90b', - 'bedrock_claude_3_5_sonnet', - ]; + 'diffbot', + 'openai-gpt-3.5', + 'openai-gpt-4o', + 'openai-gpt-4o-mini', + 'gemini-1.5-pro', + 'gemini-1.5-flash', + 'azure_ai_gpt_35', + 'azure_ai_gpt_4o', + 'ollama_llama3', + 'groq_llama3_70b', + 'anthropic_claude_3_5_sonnet', + 'fireworks_llama_v3p2_90b', + 'bedrock_claude_3_5_sonnet', + ]; export const defaultLLM = llms?.includes('openai-gpt-4o') ? 'openai-gpt-4o' : llms?.includes('gemini-1.5-pro') - ? 'gemini-1.5-pro' - : 'diffbot'; + ? 'gemini-1.5-pro' + : 'diffbot'; export const chatModeLables = { vector: 'vector', @@ -75,40 +47,40 @@ export const chatModeLables = { export const chatModes = process.env?.VITE_CHAT_MODES?.trim() != '' ? process.env.VITE_CHAT_MODES?.split(',').map((mode) => ({ - mode: mode.trim(), - description: getDescriptionForChatMode(mode.trim()), - })) + mode: mode.trim(), + description: getDescriptionForChatMode(mode.trim()), + })) : [ - { - mode: chatModeLables.vector, - description: 'Performs semantic similarity search on text chunks using vector indexing.', - }, - { - mode: chatModeLables.graph, - description: 'Translates text to Cypher queries for precise data retrieval from a graph database.', - }, - { - mode: chatModeLables.graph_vector, - description: 'Combines vector indexing and graph connections for contextually enhanced semantic search.', - }, - { - mode: chatModeLables.fulltext, - description: 'Conducts fast, keyword-based search using full-text indexing on text chunks.', - }, - { - mode: chatModeLables.graph_vector_fulltext, - description: 'Integrates vector, graph, and full-text indexing for comprehensive search results.', - }, - { - mode: chatModeLables.entity_vector, - description: 'Uses vector indexing on entity nodes for highly relevant entity-based search.', - }, - { - mode: chatModeLables.global_vector, - description: - 'Use vector and full-text indexing on community nodes to provide accurate, context-aware answers globally.', - }, - ]; + { + mode: chatModeLables.vector, + description: 'Performs semantic similarity search on text chunks using vector indexing.', + }, + { + mode: chatModeLables.graph, + description: 'Translates text to Cypher queries for precise data retrieval from a graph database.', + }, + { + mode: chatModeLables.graph_vector, + description: 'Combines vector indexing and graph connections for contextually enhanced semantic search.', + }, + { + mode: chatModeLables.fulltext, + description: 'Conducts fast, keyword-based search using full-text indexing on text chunks.', + }, + { + mode: chatModeLables.graph_vector_fulltext, + description: 'Integrates vector, graph, and full-text indexing for comprehensive search results.', + }, + { + mode: chatModeLables.entity_vector, + description: 'Uses vector indexing on entity nodes for highly relevant entity-based search.', + }, + { + mode: chatModeLables.global_vector, + description: + 'Use vector and full-text indexing on community nodes to provide accurate, context-aware answers globally.', + }, + ]; export const chunkSize = process.env.VITE_CHUNK_SIZE ? parseInt(process.env.VITE_CHUNK_SIZE) : 1 * 1024 * 1024; export const timeperpage = process.env.VITE_TIME_PER_PAGE ? parseInt(process.env.VITE_TIME_PER_PAGE) : 50; @@ -116,53 +88,6 @@ export const timePerByte = 0.2; export const largeFileSize = process.env.VITE_LARGE_FILE_SIZE ? parseInt(process.env.VITE_LARGE_FILE_SIZE) : 5 * 1024 * 1024; -export const NODES_OPTIONS = [ - { - label: 'Person', - value: 'Person', - }, - { - label: 'Organization', - value: 'Organization', - }, - { - label: 'Event', - value: 'Event', - }, -]; - -export const RELATION_OPTIONS = [ - { - label: 'WORKS_AT', - value: 'WORKS_AT', - }, - { - label: 'IS_CEO', - value: 'IS_CEO', - }, - { - label: 'HOSTS_EVENT', - value: 'HOSTS_EVENT', - }, -]; - -export const queryMap: { - Document: string; - Chunks: string; - Entities: string; - DocEntities: string; - DocChunks: string; - ChunksEntities: string; - DocChunkEntities: string; -} = { - Document: 'document', - Chunks: 'chunks', - Entities: 'entities', - DocEntities: 'docEntities', - DocChunks: 'docChunks', - ChunksEntities: 'chunksEntities', - DocChunkEntities: 'docChunkEntities', -}; export const tooltips = { generateGraph: 'Generate graph from selected files', @@ -246,6 +171,35 @@ export const RETRY_OPIONS = [ ]; export const batchSize: number = parseInt(process.env.VITE_BATCH_SIZE ?? '2'); +//Graph Constants +export const document = `+ [docs]`; + +export const chunks = `+ collect { MATCH p=(c)-[:NEXT_CHUNK]-() RETURN p } // chunk-chain ++ collect { MATCH p=(c)-[:SIMILAR]-() RETURN p } // similar-chunks`; + +export const entities = `+ collect { OPTIONAL MATCH (c:Chunk)-[:HAS_ENTITY]->(e), p=(e)-[*0..1]-(:!Chunk) RETURN p}`; + +export const docEntities = `+ [docs] ++ collect { MATCH (c:Chunk)-[:HAS_ENTITY]->(e), p=(e)--(:!Chunk) RETURN p }`; + +export const docChunks = `+[chunks] ++collect {MATCH p=(c)-[:FIRST_CHUNK]-() RETURN p} //first chunk ++ collect { MATCH p=(c)-[:NEXT_CHUNK]-() RETURN p } // chunk-chain ++ collect { MATCH p=(c)-[:SIMILAR]-() RETURN p } // similar-chunk`; + +export const chunksEntities = `+ collect { MATCH p=(c)-[:NEXT_CHUNK]-() RETURN p } // chunk-chain + ++ collect { MATCH p=(c)-[:SIMILAR]-() RETURN p } // similar-chunks +//chunks with entities ++ collect { OPTIONAL MATCH p=(c:Chunk)-[:HAS_ENTITY]->(e)-[*0..1]-(:!Chunk) RETURN p }`; + +export const docChunkEntities = `+[chunks] ++collect {MATCH p=(c)-[:FIRST_CHUNK]-() RETURN p} //first chunk ++ collect { MATCH p=(c)-[:NEXT_CHUNK]-() RETURN p } // chunk-chain ++ collect { MATCH p=(c)-[:SIMILAR]-() RETURN p } // similar-chunks +//chunks with entities ++ collect { OPTIONAL MATCH p=(c:Chunk)-[:HAS_ENTITY]->(e)-[*0..1]-(:!Chunk) RETURN p }`; + export const nvlOptions: NvlOptions = { allowDynamicMinZoom: true, disableWebGL: true, @@ -257,10 +211,22 @@ export const nvlOptions: NvlOptions = { initialZoom: 1, }; -export const mouseEventCallbacks = { - onPan: true, - onZoom: true, - onDrag: true, +export const queryMap: { + Document: string; + Chunks: string; + Entities: string; + DocEntities: string; + DocChunks: string; + ChunksEntities: string; + DocChunkEntities: string; +} = { + Document: 'document', + Chunks: 'chunks', + Entities: 'entities', + DocEntities: 'docEntities', + DocChunks: 'docChunks', + ChunksEntities: 'chunksEntities', + DocChunkEntities: 'docChunkEntities', }; // export const graphQuery: string = queryMap.DocChunkEntities; @@ -276,11 +242,6 @@ export const intitalGraphType = (isGDSActive: boolean): GraphType[] => { : ['DocumentChunk', 'Entities']; // GDS is inactive, exclude communities }; -export const appLabels = { - ownSchema: 'Or Define your own Schema', - predefinedSchema: 'Select a Pre-defined Schema', -}; - export const graphLabels = { showGraphView: 'showGraphView', chatInfoView: 'chatInfoView', @@ -310,6 +271,12 @@ export const connectionLabels = { greenStroke: 'green', redStroke: 'red', }; + export const getDefaultMessage = () => { return [{ ...chatbotmessages.listMessages[0], datetime: getDateTime() }]; }; + +export const appLabels = { + ownSchema: 'Or Define your own Schema', + predefinedSchema: 'Select a Pre-defined Schema', +}; \ No newline at end of file diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index 1d8f3be07..ae41a19fb 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -21,6 +21,7 @@ import s3logo from '../assets/images/s3logo.png'; import gcslogo from '../assets/images/gcs.webp'; import { chatModeLables } from './Constants'; + // Get the Url export const url = () => { let url = window.location.href.replace('5173', '8000'); @@ -205,7 +206,6 @@ export const filterData = ( allNodes: ExtendedNode[], allRelationships: Relationship[], scheme: Scheme, - isGdsActive: boolean ) => { let filteredNodes: ExtendedNode[] = []; let filteredRelations: Relationship[] = []; @@ -216,9 +216,7 @@ export const filterData = ( // Only Document + Chunk // const processedEntities = entityTypes.flatMap(item => item.includes(',') ? item.split(',') : item); if ( - graphType.includes('DocumentChunk') && - !graphType.includes('Entities') && - (!graphType.includes('Communities') || !isGdsActive) + graphType.includes('DocumentChunk') && !graphType.includes('Entities') && !graphType.includes('Communities') ) { filteredNodes = allNodes.filter( (node) => (node.labels.includes('Document') && node.properties.fileName) || node.labels.includes('Chunk') @@ -232,12 +230,8 @@ export const filterData = ( ); filteredScheme = { Document: scheme.Document, Chunk: scheme.Chunk }; // Only Entity - } else if ( - graphType.includes('Entities') && - !graphType.includes('DocumentChunk') && - (!graphType.includes('Communities') || !isGdsActive) - ) { - const entityNodes = allNodes.filter((node) => !node.labels.includes('Document') && !node.labels.includes('Chunk')); + } else if (graphType.includes('Entities') && !graphType.includes('DocumentChunk') && !graphType.includes('Communities')) { + const entityNodes = allNodes.filter((node) => !node.labels.includes('Document') && !node.labels.includes('Chunk') && !node.labels.includes('__Community__')); filteredNodes = entityNodes ? entityNodes : []; const nodeIds = new Set(filteredNodes.map((node) => node.id)); filteredRelations = allRelationships.filter( @@ -251,8 +245,7 @@ export const filterData = ( } else if ( graphType.includes('Communities') && !graphType.includes('DocumentChunk') && - !graphType.includes('Entities') && - isGdsActive + !graphType.includes('Entities') ) { filteredNodes = allNodes.filter((node) => node.labels.includes('__Community__')); const nodeIds = new Set(filteredNodes.map((node) => node.id)); @@ -265,7 +258,7 @@ export const filterData = ( } else if ( graphType.includes('DocumentChunk') && graphType.includes('Entities') && - (!graphType.includes('Communities') || !isGdsActive) + (!graphType.includes('Communities')) ) { filteredNodes = allNodes.filter( (node) => @@ -289,8 +282,7 @@ export const filterData = ( } else if ( graphType.includes('Entities') && graphType.includes('Communities') && - !graphType.includes('DocumentChunk') && - isGdsActive + !graphType.includes('DocumentChunk') ) { const entityNodes = allNodes.filter((node) => !node.labels.includes('Document') && !node.labels.includes('Chunk')); const communityNodes = allNodes.filter((node) => node.labels.includes('__Community__')); @@ -310,8 +302,7 @@ export const filterData = ( } else if ( graphType.includes('DocumentChunk') && graphType.includes('Communities') && - !graphType.includes('Entities') && - isGdsActive + !graphType.includes('Entities') ) { const documentChunkNodes = allNodes.filter( (node) => (node.labels.includes('Document') && node.properties.fileName) || node.labels.includes('Chunk') @@ -332,8 +323,7 @@ export const filterData = ( } else if ( graphType.includes('DocumentChunk') && graphType.includes('Entities') && - graphType.includes('Communities') && - isGdsActive + graphType.includes('Communities') ) { filteredNodes = allNodes; filteredRelations = allRelationships; @@ -475,8 +465,25 @@ export function isAllowedHost(url: string, allowedHosts: string[]) { } export const getCheckboxConditions = (allNodes: ExtendedNode[]) => { - const isDocChunk = allNodes.some((n) => n.labels?.includes('Document')); - const isEntity = allNodes.some((n) => !n.labels?.includes('Document') || !n.labels?.includes('Chunk')); - const isgds = allNodes.some((n) => n.labels?.includes('__Community__')); - return { isDocChunk, isEntity, isgds }; + const isDocChunk = allNodes.some((n) => n.labels?.includes('Document') || n.labels?.includes('Chunk')); + const isEntity = allNodes.some((n) => !n.labels?.includes('Document') && !n.labels?.includes('Chunk') && !n.labels?.includes('__Community__')); + const isCommunity = allNodes.some((n) => n.labels?.includes('__Community__')); + return { isDocChunk, isEntity, isCommunity }; }; + +export const graphTypeFromNodes = (allNodes:ExtendedNode[])=>{ + const graphType: GraphType[] =[]; + const hasDocChunk = allNodes.some((n) => n.labels?.includes('Document') || n.labels?.includes('Chunk')); + const hasEntity = allNodes.some((n) => !n.labels?.includes('Document') && !n.labels?.includes('Chunk') && !n.labels?.includes('__Community__')); + const hasCommunity = allNodes.some((n) => n.labels?.includes('__Community__')); + if(hasDocChunk){ + graphType.push('DocumentChunk'); + } + if(hasEntity){ + graphType.push('Entities'); + } + if(hasCommunity){ + graphType.push('Communities'); + } + return graphType; +} \ No newline at end of file From ba95afd9e2fe4b5f51a726c2fbb874cfc1f084fd Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Thu, 10 Oct 2024 12:49:14 +0000 Subject: [PATCH 162/292] format changes --- frontend/src/components/ChatBot/Chatbot.tsx | 459 +++++++++--------- .../components/Graph/GraphPropertiesPanel.tsx | 143 +++--- .../components/Graph/GraphPropertiesTable.tsx | 59 ++- .../src/components/Graph/GraphViewModal.tsx | 65 ++- frontend/src/components/Graph/ResizePanel.tsx | 86 ++-- .../src/components/Graph/ResultOverview.tsx | 348 +++++++------ .../Deduplication/index.tsx | 4 +- .../SelectedJobList.tsx | 4 +- frontend/src/types.ts | 3 +- frontend/src/utils/Constants.ts | 102 ++-- frontend/src/utils/Utils.ts | 42 +- 11 files changed, 646 insertions(+), 669 deletions(-) diff --git a/frontend/src/components/ChatBot/Chatbot.tsx b/frontend/src/components/ChatBot/Chatbot.tsx index 7a8b64a73..9e3ba07f6 100644 --- a/frontend/src/components/ChatBot/Chatbot.tsx +++ b/frontend/src/components/ChatBot/Chatbot.tsx @@ -245,7 +245,7 @@ const Chatbot: FC = (props) => { } else { setListMessages((prev) => prev.map((msg) => - (msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg) + msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg ) ); } @@ -260,7 +260,7 @@ const Chatbot: FC = (props) => { } else { setListMessages((prev) => prev.map((msg) => - (msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg) + msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg ) ); } @@ -269,15 +269,15 @@ const Chatbot: FC = (props) => { console.error(`API call failed for mode ${mode}:`, result.reason); setListMessages((prev) => prev.map((msg) => - (msg.id === chatbotMessageId + msg.id === chatbotMessageId ? { - ...msg, - modes: { - ...msg.modes, - [mode]: { message: 'Failed to fetch response for this mode.', error: result.reason }, - }, - } - : msg) + ...msg, + modes: { + ...msg.modes, + [mode]: { message: 'Failed to fetch response for this mode.', error: result.reason }, + }, + } + : msg ) ); } @@ -290,19 +290,19 @@ const Chatbot: FC = (props) => { if (error instanceof Error) { setListMessages((prev) => prev.map((msg) => - (msg.id === chatbotMessageId + msg.id === chatbotMessageId ? { - ...msg, - isLoading: false, - isTyping: false, - modes: { - [chatModes[0]]: { - message: 'An error occurred while processing your request.', - error: error.message, - }, + ...msg, + isLoading: false, + isTyping: false, + modes: { + [chatModes[0]]: { + message: 'An error occurred while processing your request.', + error: error.message, }, - } - : msg) + }, + } + : msg ) ); } @@ -409,78 +409,100 @@ const Chatbot: FC = (props) => { } }, []); - return ( -
    -
    - -
    - {listMessages.map((chat, index) => { - const messagechatModes = Object.keys(chat.modes); - return ( -
    -
    - {chat.user === 'chatbot' ? ( - - ) : ( - - )} -
    - +
    + +
    + {listMessages.map((chat, index) => { + const messagechatModes = Object.keys(chat.modes); + return ( +
    +
    + {chat.user === 'chatbot' ? ( + + ) : ( + + )} +
    + -
    +
    - - {chat.modes[chat.currentMode]?.message || ''} - -
    + > + + {chat.modes[chat.currentMode]?.message || ''} + +
    +
    -
    - - {chat.datetime} - -
    - {chat.user === 'chatbot' && - chat.id !== 2 && - !chat.isLoading && - !chat.isTyping && - (!isFullScreen ? ( - 1 ? 'space-between' : 'unset'} - alignItems='center' - > + + {chat.datetime} + +
    + {chat.user === 'chatbot' && + chat.id !== 2 && + !chat.isLoading && + !chat.isTyping && + (!isFullScreen ? ( + 1 ? 'space-between' : 'unset'} + alignItems='center' + > + + {messagechatModes.length > 1 && ( + { + const modes = Object.keys(chat.modes); + const modeswtich = modes[index]; + handleSwitchMode(chat.id, modeswtich); + }} + isFullScreen={false} + currentModeIndex={messagechatModes.indexOf(chat.currentMode)} + modescount={messagechatModes.length} + /> + )} + + ) : ( + + = (props) => { listMessages={listMessages} speechHandler={speechHandler} > + + {messagechatModes.length > 1 && ( = (props) => { const modeswtich = modes[index]; handleSwitchMode(chat.id, modeswtich); }} - isFullScreen={false} + isFullScreen={isFullScreen} currentModeIndex={messagechatModes.indexOf(chat.currentMode)} modescount={messagechatModes.length} /> )} - - ) : ( - - - - - - {messagechatModes.length > 1 && ( - { - const modes = Object.keys(chat.modes); - const modeswtich = modes[index]; - handleSwitchMode(chat.id, modeswtich); - }} - isFullScreen={isFullScreen} - currentModeIndex={messagechatModes.indexOf(chat.currentMode)} - modescount={messagechatModes.length} - /> - )} - - - ))} -
    -
    -
    - ); - })} -
    -
    -
    -
    -
    - + + ))} +
    +
    +
    + ); + })} +
    +
    +
    +
    + + - - {buttonCaptions.ask}{' '} - {selectedFileNames != undefined && selectedFileNames.length > 0 && `(${selectedFileNames.length})`} - - -
    - }> - setShowInfoModal(false)} - open={showInfoModal} + aria-label='chatbot-input' + type='text' + value={inputMessage} + fluid + onChange={handleInputChange} + name='chatbot-input' + /> + -
    - { - downloadClickHandler({ - chatResponse: activeChat, - chunks, - metricDetails, - communities, - responseTime, - entities: infoEntities, - nodes, - tokensUsed, - model, - }); - }} - > - - - "" - - - setShowInfoModal(false)} - > - - -
    - -
    -
    + {buttonCaptions.ask}{' '} + {selectedFileNames != undefined && selectedFileNames.length > 0 && `(${selectedFileNames.length})`} + +
    - ); + }> + setShowInfoModal(false)} + open={showInfoModal} + > +
    + { + downloadClickHandler({ + chatResponse: activeChat, + chunks, + metricDetails, + communities, + responseTime, + entities: infoEntities, + nodes, + tokensUsed, + model, + }); + }} + > + + + "" + + + setShowInfoModal(false)} + > + + +
    + +
    +
    +
    +); }; export default Chatbot; diff --git a/frontend/src/components/Graph/GraphPropertiesPanel.tsx b/frontend/src/components/Graph/GraphPropertiesPanel.tsx index 276160b69..64332c9ac 100644 --- a/frontend/src/components/Graph/GraphPropertiesPanel.tsx +++ b/frontend/src/components/Graph/GraphPropertiesPanel.tsx @@ -4,88 +4,81 @@ import { BasicNode, BasicRelationship, GraphPropertiesPanelProps } from '../../t import { LegendsChip } from './LegendsChip'; import GraphPropertiesTable from './GraphPropertiesTable'; - const sortAlphabetically = (a: string, b: string) => a.toLowerCase().localeCompare(b.toLowerCase()); const isNode = (item: BasicNode | BasicRelationship): item is BasicNode => { - return 'labels' in item && !('from' in item) && !('to' in item); + return 'labels' in item && !('from' in item) && !('to' in item); }; const GraphPropertiesPanel = ({ inspectedItem, newScheme }: GraphPropertiesPanelProps) => { - const inspectedItemType = isNode(inspectedItem) ? 'node' : 'relationship'; - const properties = inspectedItemType === 'node' - ? [ - { - key: '', - value: `${(inspectedItem as BasicNode).id}`, - type: 'String', - }, - ...Object.keys((inspectedItem as BasicNode).properties).map((key) => { - const value = (inspectedItem as BasicNode).properties[key]; - return { key: key, value: value ?? '' }; - }), + const inspectedItemType = isNode(inspectedItem) ? 'node' : 'relationship'; + const properties = + inspectedItemType === 'node' + ? [ + { + key: '', + value: `${(inspectedItem as BasicNode).id}`, + type: 'String', + }, + ...Object.keys((inspectedItem as BasicNode).properties).map((key) => { + const value = (inspectedItem as BasicNode).properties[key]; + return { key: key, value: value ?? '' }; + }), ] - : [ - { - key: '', - value: `${(inspectedItem as BasicRelationship).id}`, - type: 'String', - }, - { - key: '', - value: `${(inspectedItem as BasicRelationship).from}`, - type: 'String', - }, - { - key: '', - value: `${(inspectedItem as BasicRelationship).to}`, - type: 'String', - }, - { - key: '', - value: `${(inspectedItem as BasicRelationship).caption ?? ''}`, - type: 'String', - }, + : [ + { + key: '', + value: `${(inspectedItem as BasicRelationship).id}`, + type: 'String', + }, + { + key: '', + value: `${(inspectedItem as BasicRelationship).from}`, + type: 'String', + }, + { + key: '', + value: `${(inspectedItem as BasicRelationship).to}`, + type: 'String', + }, + { + key: '', + value: `${(inspectedItem as BasicRelationship).caption ?? ''}`, + type: 'String', + }, ]; - const labelsSorted = useMemo(() => { - if (isNode(inspectedItem)) { - return [...inspectedItem.labels].sort(sortAlphabetically); - } - return []; - }, [inspectedItem]); + const labelsSorted = useMemo(() => { + if (isNode(inspectedItem)) { + return [...inspectedItem.labels].sort(sortAlphabetically); + } + return []; + }, [inspectedItem]); - return ( - <> - -
    - {inspectedItemType === 'node' ? 'Node details' : 'Relationship details'} -
    -
    - -
    - {isNode(inspectedItem) ? ( - labelsSorted.map((label) => ( - - )) - ) : ( - - )} -
    -
    - - - - ); -} + return ( + <> + +
    {inspectedItemType === 'node' ? 'Node details' : 'Relationship details'}
    +
    + +
    + {isNode(inspectedItem) ? ( + labelsSorted.map((label) => ( + + )) + ) : ( + + )} +
    +
    + + + + ); +}; -export default GraphPropertiesPanel; \ No newline at end of file +export default GraphPropertiesPanel; diff --git a/frontend/src/components/Graph/GraphPropertiesTable.tsx b/frontend/src/components/Graph/GraphPropertiesTable.tsx index 8cd7571c7..7600ccd35 100644 --- a/frontend/src/components/Graph/GraphPropertiesTable.tsx +++ b/frontend/src/components/Graph/GraphPropertiesTable.tsx @@ -2,38 +2,33 @@ import { GraphLabel, Typography } from '@neo4j-ndl/react'; import { GraphPropertiesTableProps } from '../../types'; const GraphPropertiesTable = ({ propertiesWithTypes }: GraphPropertiesTableProps): JSX.Element => { - console.log('props', propertiesWithTypes); - return ( -
    -
    - - Key - - Value + console.log('props', propertiesWithTypes); + return ( +
    +
    + + Key + + Value +
    + {propertiesWithTypes.map(({ key, value }, _) => { + return ( +
    +
    + + {key} +
    - {propertiesWithTypes.map(({ key, value }, _) => { - return ( -
    -
    - - {key} - -
    -
    - {value} -
    -
    - ); - })} -
    - ); +
    {value}
    +
    + ); + })} +
    + ); }; -export default GraphPropertiesTable; \ No newline at end of file +export default GraphPropertiesTable; diff --git a/frontend/src/components/Graph/GraphViewModal.tsx b/frontend/src/components/Graph/GraphViewModal.tsx index cb995a014..dddfb4175 100644 --- a/frontend/src/components/Graph/GraphViewModal.tsx +++ b/frontend/src/components/Graph/GraphViewModal.tsx @@ -1,11 +1,4 @@ -import { - Banner, - Dialog, - Flex, - IconButtonArray, - LoadingSpinner, - useDebounce, -} from '@neo4j-ndl/react'; +import { Banner, Dialog, Flex, IconButtonArray, LoadingSpinner, useDebounce } from '@neo4j-ndl/react'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { BasicNode, @@ -32,19 +25,13 @@ import { filterData, getCheckboxConditions, graphTypeFromNodes, processGraphData import { useCredentials } from '../../context/UserCredentials'; import graphQueryAPI from '../../services/GraphQuery'; -import { - graphLabels, - intitalGraphType, - nvlOptions, - queryMap, -} from '../../utils/Constants'; +import { graphLabels, nvlOptions, queryMap } from '../../utils/Constants'; import CheckboxSelection from './CheckboxSelection'; import ResultOverview from './ResultOverview'; import { ResizePanelDetails } from './ResizePanel'; import GraphPropertiesPanel from './GraphPropertiesPanel'; - const GraphViewModal: React.FunctionComponent = ({ open, inspectedName, @@ -75,10 +62,10 @@ const GraphViewModal: React.FunctionComponent = ({ graphType.includes('DocumentChunk') && graphType.includes('Entities') ? queryMap.DocChunkEntities : graphType.includes('DocumentChunk') - ? queryMap.DocChunks - : graphType.includes('Entities') - ? queryMap.Entities - : ''; + ? queryMap.DocChunks + : graphType.includes('Entities') + ? queryMap.Entities + : ''; // fit graph to original position const handleZoomToFit = () => { @@ -87,7 +74,7 @@ const GraphViewModal: React.FunctionComponent = ({ {} ); }; -console.log('graphType', graphType); + console.log('graphType', graphType); // Unmounting the component useEffect(() => { const timeoutId = setTimeout(() => { @@ -114,17 +101,17 @@ console.log('graphType', graphType); if (Array.isArray(updateGraphType)) { setGraphType(updateGraphType); } - }, [allNodes]) + }, [allNodes]); const fetchData = useCallback(async () => { try { const nodeRelationshipData = viewPoint === graphLabels.showGraphView ? await graphQueryAPI( - userCredentials as UserCredentials, - graphQuery, - selectedRows?.map((f) => f.name) - ) + userCredentials as UserCredentials, + graphQuery, + selectedRows?.map((f) => f.name) + ) : await graphQueryAPI(userCredentials as UserCredentials, graphQuery, [inspectedName ?? '']); return nodeRelationshipData; } catch (error: any) { @@ -204,7 +191,7 @@ console.log('graphType', graphType); graphType, finalNodes ?? [], finalRels ?? [], - schemeVal, + schemeVal ); setNodes(filteredNodes); setRelationships(filteredRelations); @@ -212,7 +199,6 @@ console.log('graphType', graphType); } }; - const selectedItem = useMemo(() => { if (selected === undefined) { return undefined; @@ -245,8 +231,8 @@ console.log('graphType', graphType); match && viewPoint === graphLabels.showGraphView ? 100 : match && viewPoint !== graphLabels.showGraphView - ? 50 - : graphLabels.nodeSize, + ? 50 + : graphLabels.nodeSize, }; }); // deactivating any active relationships @@ -293,7 +279,7 @@ console.log('graphType', graphType); } }; - //Callback + // Callback const nvlCallbacks = { onLayoutComputing(isComputing: boolean) { if (!isComputing) { @@ -337,7 +323,6 @@ console.log('graphType', graphType); setSelected(undefined); }; - const mouseEventCallbacks = { onNodeClick: (clickedNode: Node) => { setSelected({ type: 'node', id: clickedNode.id }); @@ -442,10 +427,22 @@ console.log('graphType', graphType);
    {selectedItem !== undefined ? ( - + ) : ( - )} + + )}
    diff --git a/frontend/src/components/Graph/ResizePanel.tsx b/frontend/src/components/Graph/ResizePanel.tsx index 049b782f1..a0eac1a7e 100644 --- a/frontend/src/components/Graph/ResizePanel.tsx +++ b/frontend/src/components/Graph/ResizePanel.tsx @@ -3,54 +3,52 @@ import type { ResizeCallback } from 're-resizable'; import { Resizable } from 're-resizable'; type ResizePanelProps = { - children: React.ReactNode; - open: boolean; - onResizeStop?: ResizeCallback; - defaultWidth?: number; + children: React.ReactNode; + open: boolean; + onResizeStop?: ResizeCallback; + defaultWidth?: number; }; export const ResizePanelDetails = ({ children, open, onResizeStop }: ResizePanelProps) => { - if (!open) { - return null; - } - return ( - }} - handleClasses={{ left: 'ml-1' }} - onResizeStop={onResizeStop} - > -
    - {children} -
    -
    - ); -} + if (!open) { + return null; + } + return ( + }} + handleClasses={{ left: 'ml-1' }} + onResizeStop={onResizeStop} + > +
    {children}
    +
    + ); +}; const Title = ({ children }: { children: React.ReactNode }) => { - return ( -
    - {children} -
    - ); -} + return ( +
    + {children} +
    + ); +}; ResizePanelDetails.Title = Title; const Content = ({ children }: { children: React.ReactNode }) => { - return
    {children}
    ; -} -ResizePanelDetails.Content = Content; \ No newline at end of file + return
    {children}
    ; +}; +ResizePanelDetails.Content = Content; diff --git a/frontend/src/components/Graph/ResultOverview.tsx b/frontend/src/components/Graph/ResultOverview.tsx index 1f755d188..93c6b54e3 100644 --- a/frontend/src/components/Graph/ResultOverview.tsx +++ b/frontend/src/components/Graph/ResultOverview.tsx @@ -1,197 +1,187 @@ - import { Flex, IconButton, TextInput, Typography } from '@neo4j-ndl/react'; -import { MagnifyingGlassIconOutline } from "@neo4j-ndl/react/icons"; +import { MagnifyingGlassIconOutline } from '@neo4j-ndl/react/icons'; import { LegendsChip } from './LegendsChip'; -import { - ExtendedNode, - ExtendedRelationship, - Scheme, -} from '../../types'; -import { - graphLabels, - RESULT_STEP_SIZE, -} from '../../utils/Constants'; +import { ExtendedNode, ExtendedRelationship, Scheme } from '../../types'; +import { graphLabels, RESULT_STEP_SIZE } from '../../utils/Constants'; import type { Relationship } from '@neo4j-nvl/base'; import { ShowAll } from '../UI/ShowAll'; -import { sortAlphabetically } from "../../utils/Utils"; -import { Dispatch, SetStateAction } from "react"; +import { sortAlphabetically } from '../../utils/Utils'; +import { Dispatch, SetStateAction } from 'react'; interface OverViewProps { - nodes: ExtendedNode[]; - relationships: ExtendedRelationship[]; - newScheme: Scheme; - searchQuery: string - setSearchQuery: Dispatch> - viewPoint: string, - setNodes: Dispatch>, - setRelationships: Dispatch> + nodes: ExtendedNode[]; + relationships: ExtendedRelationship[]; + newScheme: Scheme; + searchQuery: string; + setSearchQuery: Dispatch>; + viewPoint: string; + setNodes: Dispatch>; + setRelationships: Dispatch>; } -const ResultOverview: React.FunctionComponent = ({ nodes, relationships, newScheme, searchQuery, setSearchQuery, viewPoint, setNodes, setRelationships }) => { - const nodeCount = (nodes: ExtendedNode[], label: string): number => { - return [...new Set(nodes?.filter((n) => n.labels?.includes(label)).map((i) => i.id))].length; - }; - - // sort the legends in with Chunk and Document always the first two values - const nodeCheck = Object.keys(newScheme).sort((a, b) => { - if (a === graphLabels.document || a === graphLabels.chunk) { - return -1; - } else if (b === graphLabels.document || b === graphLabels.chunk) { - return 1; - } - return a.localeCompare(b); - }); +const ResultOverview: React.FunctionComponent = ({ + nodes, + relationships, + newScheme, + searchQuery, + setSearchQuery, + viewPoint, + setNodes, + setRelationships, +}) => { + const nodeCount = (nodes: ExtendedNode[], label: string): number => { + return [...new Set(nodes?.filter((n) => n.labels?.includes(label)).map((i) => i.id))].length; + }; - // get sorted relationships - const relationshipsSorted = relationships.sort(sortAlphabetically); + // sort the legends in with Chunk and Document always the first two values + const nodeCheck = Object.keys(newScheme).sort((a, b) => { + if (a === graphLabels.document || a === graphLabels.chunk) { + return -1; + } else if (b === graphLabels.document || b === graphLabels.chunk) { + return 1; + } + return a.localeCompare(b); + }); + // get sorted relationships + const relationshipsSorted = relationships.sort(sortAlphabetically); - const relationshipCount = (relationships: ExtendedRelationship[], label: string): number => { - return [...new Set(relationships?.filter((r) => r.caption?.includes(label)).map((i) => i.id))].length; - }; + const relationshipCount = (relationships: ExtendedRelationship[], label: string): number => { + return [...new Set(relationships?.filter((r) => r.caption?.includes(label)).map((i) => i.id))].length; + }; - // To get the relationship count - const groupedAndSortedRelationships: ExtendedRelationship[] = Object.values( - relationshipsSorted.reduce((acc: { [key: string]: ExtendedRelationship }, relType: Relationship) => { - const key = relType.caption || ''; - if (!acc[key]) { - acc[key] = { ...relType, count: 0 }; - } - (acc[key] as { count: number }).count += relationshipCount(relationships as ExtendedRelationship[], key); - return acc; - }, {}) - ); - - // On Relationship Legend Click, highlight the relationships and deactivating any active nodes - const handleRelationshipClick = (nodeLabel: string) => { - const updatedRelations = relationships.map((rel) => { - return { - ...rel, - selected: rel?.caption?.includes(nodeLabel), - }; - }); - - // // deactivating any active nodes - const updatedNodes = nodes.map((node) => { - return { - ...node, - selected: false, - size: graphLabels.nodeSize, - }; - }); - if (searchQuery !== '') { - setSearchQuery(''); - } - setRelationships(updatedRelations); - setNodes(updatedNodes); - }; + // To get the relationship count + const groupedAndSortedRelationships: ExtendedRelationship[] = Object.values( + relationshipsSorted.reduce((acc: { [key: string]: ExtendedRelationship }, relType: Relationship) => { + const key = relType.caption || ''; + if (!acc[key]) { + acc[key] = { ...relType, count: 0 }; + } + (acc[key] as { count: number }).count += relationshipCount(relationships as ExtendedRelationship[], key); + return acc; + }, {}) + ); + // On Relationship Legend Click, highlight the relationships and deactivating any active nodes + const handleRelationshipClick = (nodeLabel: string) => { + const updatedRelations = relationships.map((rel) => { + return { + ...rel, + selected: rel?.caption?.includes(nodeLabel), + }; + }); + // // deactivating any active nodes + const updatedNodes = nodes.map((node) => { + return { + ...node, + selected: false, + size: graphLabels.nodeSize, + }; + }); + if (searchQuery !== '') { + setSearchQuery(''); + } + setRelationships(updatedRelations); + setNodes(updatedNodes); + }; - // On Node Click, highlighting the nodes and deactivating any active relationships - const handleNodeClick = (nodeLabel: string) => { - const updatedNodes = nodes.map((node) => { - const isActive = node.labels.includes(nodeLabel); - return { - ...node, - selected: isActive, - size: - isActive && viewPoint === graphLabels.showGraphView - ? 100 - : isActive && viewPoint !== graphLabels.showGraphView - ? 50 - : graphLabels.nodeSize, - }; - }); - // deactivating any active relationships - const updatedRelationships = relationships.map((rel) => { - return { - ...rel, - selected: false, - }; - }); - if (searchQuery !== '') { - setSearchQuery(''); - } - setNodes(updatedNodes); - setRelationships(updatedRelationships); - }; + // On Node Click, highlighting the nodes and deactivating any active relationships + const handleNodeClick = (nodeLabel: string) => { + const updatedNodes = nodes.map((node) => { + const isActive = node.labels.includes(nodeLabel); + return { + ...node, + selected: isActive, + size: + isActive && viewPoint === graphLabels.showGraphView + ? 100 + : isActive && viewPoint !== graphLabels.showGraphView + ? 50 + : graphLabels.nodeSize, + }; + }); + // deactivating any active relationships + const updatedRelationships = relationships.map((rel) => { + return { + ...rel, + selected: false, + }; + }); + if (searchQuery !== '') { + setSearchQuery(''); + } + setNodes(updatedNodes); + setRelationships(updatedRelationships); + }; - return ( + return ( + <> + {nodeCheck.length > 0 && ( <> - {nodeCheck.length > 0 && ( - <> - - {graphLabels.resultOverview} -
    - { - setSearchQuery(e.target.value); - }} - placeholder='Search On Node Properties' - fluid={true} - leftIcon={ - - - - } - /> -
    - - {graphLabels.totalNodes} ({nodes.length}) - -
    -
    - - {nodeCheck.map((nodeLabel, index) => ( - handleNodeClick(nodeLabel)} - /> - ))} - -
    - - )} - {relationshipsSorted.length > 0 && ( - <> - - - {graphLabels.totalRelationships} ({relationships.length}) - - -
    - - {groupedAndSortedRelationships.map((relType, index) => ( - handleRelationshipClick(relType.caption || '')} - scheme={{}} /> - ))} - -
    - - )} + + {graphLabels.resultOverview} +
    + { + setSearchQuery(e.target.value); + }} + placeholder='Search On Node Properties' + fluid={true} + leftIcon={ + + + + } + /> +
    + + {graphLabels.totalNodes} ({nodes.length}) + +
    +
    + + {nodeCheck.map((nodeLabel, index) => ( + handleNodeClick(nodeLabel)} + /> + ))} + +
    - ) -} + )} + {relationshipsSorted.length > 0 && ( + <> + + + {graphLabels.totalRelationships} ({relationships.length}) + + +
    + + {groupedAndSortedRelationships.map((relType, index) => ( + handleRelationshipClick(relType.caption || '')} + scheme={{}} + /> + ))} + +
    + + )} + + ); +}; -export default ResultOverview; \ No newline at end of file +export default ResultOverview; diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx index f5a021e30..36fcff3d1 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx @@ -80,12 +80,12 @@ export default function DeduplicationTab() { const onRemove = (nodeid: string, similarNodeId: string) => { setDuplicateNodes((prev) => { return prev.map((d) => - (d.e.elementId === nodeid + d.e.elementId === nodeid ? { ...d, similar: d.similar.filter((n) => n.elementId != similarNodeId), } - : d) + : d ); }); }; diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx index 1cb3c7310..a7621f2b6 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx @@ -11,11 +11,11 @@ export default function SelectedJobList({ }) { const ongoingPostProcessingTasks = useMemo( () => - (isGdsActive + isGdsActive ? postProcessingTasks.includes('enable_communities') ? postProcessingTasks : postProcessingTasks.filter((s) => s != 'enable_communities') - : postProcessingTasks.filter((s) => s != 'enable_communities')), + : postProcessingTasks.filter((s) => s != 'enable_communities'), [isGdsActive, postProcessingTasks] ); return ( diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 392754d77..54deb12b9 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -244,7 +244,7 @@ export type ChatbotProps = { isFullScreen?: boolean; connectionStatus: boolean; }; -export interface WikipediaModalTypes extends Omit { } +export interface WikipediaModalTypes extends Omit {} export interface GraphViewModalProps { open: boolean; @@ -791,7 +791,6 @@ export type BasicNode = { propertyTypes: Record; }; - export type GraphPropertiesTableProps = { propertiesWithTypes: { key: string; diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index 34e1b7263..3eb3a1fe8 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -12,26 +12,26 @@ export const llms = process.env?.VITE_LLM_MODELS?.trim() != '' ? (process.env.VITE_LLM_MODELS?.split(',') as string[]) : [ - 'diffbot', - 'openai-gpt-3.5', - 'openai-gpt-4o', - 'openai-gpt-4o-mini', - 'gemini-1.5-pro', - 'gemini-1.5-flash', - 'azure_ai_gpt_35', - 'azure_ai_gpt_4o', - 'ollama_llama3', - 'groq_llama3_70b', - 'anthropic_claude_3_5_sonnet', - 'fireworks_llama_v3p2_90b', - 'bedrock_claude_3_5_sonnet', - ]; + 'diffbot', + 'openai-gpt-3.5', + 'openai-gpt-4o', + 'openai-gpt-4o-mini', + 'gemini-1.5-pro', + 'gemini-1.5-flash', + 'azure_ai_gpt_35', + 'azure_ai_gpt_4o', + 'ollama_llama3', + 'groq_llama3_70b', + 'anthropic_claude_3_5_sonnet', + 'fireworks_llama_v3p2_90b', + 'bedrock_claude_3_5_sonnet', + ]; export const defaultLLM = llms?.includes('openai-gpt-4o') ? 'openai-gpt-4o' : llms?.includes('gemini-1.5-pro') - ? 'gemini-1.5-pro' - : 'diffbot'; + ? 'gemini-1.5-pro' + : 'diffbot'; export const chatModeLables = { vector: 'vector', @@ -47,40 +47,40 @@ export const chatModeLables = { export const chatModes = process.env?.VITE_CHAT_MODES?.trim() != '' ? process.env.VITE_CHAT_MODES?.split(',').map((mode) => ({ - mode: mode.trim(), - description: getDescriptionForChatMode(mode.trim()), - })) + mode: mode.trim(), + description: getDescriptionForChatMode(mode.trim()), + })) : [ - { - mode: chatModeLables.vector, - description: 'Performs semantic similarity search on text chunks using vector indexing.', - }, - { - mode: chatModeLables.graph, - description: 'Translates text to Cypher queries for precise data retrieval from a graph database.', - }, - { - mode: chatModeLables.graph_vector, - description: 'Combines vector indexing and graph connections for contextually enhanced semantic search.', - }, - { - mode: chatModeLables.fulltext, - description: 'Conducts fast, keyword-based search using full-text indexing on text chunks.', - }, - { - mode: chatModeLables.graph_vector_fulltext, - description: 'Integrates vector, graph, and full-text indexing for comprehensive search results.', - }, - { - mode: chatModeLables.entity_vector, - description: 'Uses vector indexing on entity nodes for highly relevant entity-based search.', - }, - { - mode: chatModeLables.global_vector, - description: - 'Use vector and full-text indexing on community nodes to provide accurate, context-aware answers globally.', - }, - ]; + { + mode: chatModeLables.vector, + description: 'Performs semantic similarity search on text chunks using vector indexing.', + }, + { + mode: chatModeLables.graph, + description: 'Translates text to Cypher queries for precise data retrieval from a graph database.', + }, + { + mode: chatModeLables.graph_vector, + description: 'Combines vector indexing and graph connections for contextually enhanced semantic search.', + }, + { + mode: chatModeLables.fulltext, + description: 'Conducts fast, keyword-based search using full-text indexing on text chunks.', + }, + { + mode: chatModeLables.graph_vector_fulltext, + description: 'Integrates vector, graph, and full-text indexing for comprehensive search results.', + }, + { + mode: chatModeLables.entity_vector, + description: 'Uses vector indexing on entity nodes for highly relevant entity-based search.', + }, + { + mode: chatModeLables.global_vector, + description: + 'Use vector and full-text indexing on community nodes to provide accurate, context-aware answers globally.', + }, + ]; export const chunkSize = process.env.VITE_CHUNK_SIZE ? parseInt(process.env.VITE_CHUNK_SIZE) : 1 * 1024 * 1024; export const timeperpage = process.env.VITE_TIME_PER_PAGE ? parseInt(process.env.VITE_TIME_PER_PAGE) : 50; @@ -171,7 +171,7 @@ export const RETRY_OPIONS = [ ]; export const batchSize: number = parseInt(process.env.VITE_BATCH_SIZE ?? '2'); -//Graph Constants +// Graph Constants export const document = `+ [docs]`; export const chunks = `+ collect { MATCH p=(c)-[:NEXT_CHUNK]-() RETURN p } // chunk-chain @@ -279,4 +279,4 @@ export const getDefaultMessage = () => { export const appLabels = { ownSchema: 'Or Define your own Schema', predefinedSchema: 'Select a Pre-defined Schema', -}; \ No newline at end of file +}; diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index ae41a19fb..9a5bec5a8 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -21,7 +21,6 @@ import s3logo from '../assets/images/s3logo.png'; import gcslogo from '../assets/images/gcs.webp'; import { chatModeLables } from './Constants'; - // Get the Url export const url = () => { let url = window.location.href.replace('5173', '8000'); @@ -205,7 +204,7 @@ export const filterData = ( graphType: GraphType[], allNodes: ExtendedNode[], allRelationships: Relationship[], - scheme: Scheme, + scheme: Scheme ) => { let filteredNodes: ExtendedNode[] = []; let filteredRelations: Relationship[] = []; @@ -215,9 +214,7 @@ export const filterData = ( ); // Only Document + Chunk // const processedEntities = entityTypes.flatMap(item => item.includes(',') ? item.split(',') : item); - if ( - graphType.includes('DocumentChunk') && !graphType.includes('Entities') && !graphType.includes('Communities') - ) { + if (graphType.includes('DocumentChunk') && !graphType.includes('Entities') && !graphType.includes('Communities')) { filteredNodes = allNodes.filter( (node) => (node.labels.includes('Document') && node.properties.fileName) || node.labels.includes('Chunk') ); @@ -230,8 +227,15 @@ export const filterData = ( ); filteredScheme = { Document: scheme.Document, Chunk: scheme.Chunk }; // Only Entity - } else if (graphType.includes('Entities') && !graphType.includes('DocumentChunk') && !graphType.includes('Communities')) { - const entityNodes = allNodes.filter((node) => !node.labels.includes('Document') && !node.labels.includes('Chunk') && !node.labels.includes('__Community__')); + } else if ( + graphType.includes('Entities') && + !graphType.includes('DocumentChunk') && + !graphType.includes('Communities') + ) { + const entityNodes = allNodes.filter( + (node) => + !node.labels.includes('Document') && !node.labels.includes('Chunk') && !node.labels.includes('__Community__') + ); filteredNodes = entityNodes ? entityNodes : []; const nodeIds = new Set(filteredNodes.map((node) => node.id)); filteredRelations = allRelationships.filter( @@ -258,7 +262,7 @@ export const filterData = ( } else if ( graphType.includes('DocumentChunk') && graphType.includes('Entities') && - (!graphType.includes('Communities')) + !graphType.includes('Communities') ) { filteredNodes = allNodes.filter( (node) => @@ -388,7 +392,7 @@ export const isFileCompleted = (waitingFile: CustomFile, item: SourceNode) => waitingFile && item.status === 'Completed'; export const calculateProcessedCount = (prev: number, batchSize: number) => - (prev === batchSize ? batchSize - 1 : prev + 1); + prev === batchSize ? batchSize - 1 : prev + 1; export const isProcessingFileValid = (item: SourceNode, userCredentials: UserCredentials) => { return item.status === 'Processing' && item.fileName != undefined && userCredentials && userCredentials.database; @@ -466,24 +470,28 @@ export function isAllowedHost(url: string, allowedHosts: string[]) { export const getCheckboxConditions = (allNodes: ExtendedNode[]) => { const isDocChunk = allNodes.some((n) => n.labels?.includes('Document') || n.labels?.includes('Chunk')); - const isEntity = allNodes.some((n) => !n.labels?.includes('Document') && !n.labels?.includes('Chunk') && !n.labels?.includes('__Community__')); + const isEntity = allNodes.some( + (n) => !n.labels?.includes('Document') && !n.labels?.includes('Chunk') && !n.labels?.includes('__Community__') + ); const isCommunity = allNodes.some((n) => n.labels?.includes('__Community__')); return { isDocChunk, isEntity, isCommunity }; }; -export const graphTypeFromNodes = (allNodes:ExtendedNode[])=>{ - const graphType: GraphType[] =[]; +export const graphTypeFromNodes = (allNodes: ExtendedNode[]) => { + const graphType: GraphType[] = []; const hasDocChunk = allNodes.some((n) => n.labels?.includes('Document') || n.labels?.includes('Chunk')); - const hasEntity = allNodes.some((n) => !n.labels?.includes('Document') && !n.labels?.includes('Chunk') && !n.labels?.includes('__Community__')); + const hasEntity = allNodes.some( + (n) => !n.labels?.includes('Document') && !n.labels?.includes('Chunk') && !n.labels?.includes('__Community__') + ); const hasCommunity = allNodes.some((n) => n.labels?.includes('__Community__')); - if(hasDocChunk){ + if (hasDocChunk) { graphType.push('DocumentChunk'); } - if(hasEntity){ + if (hasEntity) { graphType.push('Entities'); } - if(hasCommunity){ + if (hasCommunity) { graphType.push('Communities'); } return graphType; -} \ No newline at end of file +}; From 0cc118d01b1ba73a0efaed7956fa1848da065244 Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Thu, 10 Oct 2024 19:35:38 +0530 Subject: [PATCH 163/292] Communities Bug fixes (#775) * added global search+vector+fulltext mode * added community details in chunk entities * added node ids * updated vector graph query * added entities and modified chat response * added params * api response changes * added chunk entity query * modifies query * labels cahnge for nodes * payload changes * added nodetails properties * payload new changes * communities check * communities selecetion check * enable communities * removed the selected prop * enable communities label change * communities name change * cred check * tooltip * fix: Copy Icon Theme Fix --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> --- backend/score.py | 1 + .../src/components/ChatBot/ChatModeToggle.tsx | 3 +- .../src/components/ChatBot/Communities.tsx | 1 + .../components/ChatBot/CommunitiesInfo.tsx | 40 +++++++++++++ frontend/src/components/Content.tsx | 13 +++- frontend/src/components/FileTable.tsx | 60 +++++++++++++++---- frontend/src/components/Layout/SideNav.tsx | 2 +- frontend/src/utils/Constants.ts | 2 +- frontend/src/utils/Utils.ts | 2 + 9 files changed, 108 insertions(+), 16 deletions(-) create mode 100644 frontend/src/components/ChatBot/CommunitiesInfo.tsx diff --git a/backend/score.py b/backend/score.py index 920fa00f9..a2ffd033f 100644 --- a/backend/score.py +++ b/backend/score.py @@ -423,6 +423,7 @@ async def upload_large_file_into_chunks(file:UploadFile = File(...), chunkNumber elapsed_time = end - start json_obj = {'api_name':'upload','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc)), 'elapsed_api_time':f'{elapsed_time:.2f}'} logger.log_struct(json_obj, "INFO") + # result['elapsed_api_time'] = f'{elapsed_time:.2f}' if int(chunkNumber) == int(totalChunks): return create_api_response('Success',data=result, message='Source Node Created Successfully') else: diff --git a/frontend/src/components/ChatBot/ChatModeToggle.tsx b/frontend/src/components/ChatBot/ChatModeToggle.tsx index 127942c57..01e2d1aa7 100644 --- a/frontend/src/components/ChatBot/ChatModeToggle.tsx +++ b/frontend/src/components/ChatBot/ChatModeToggle.tsx @@ -22,7 +22,7 @@ export default function ChatModeToggle({ }) { const { setchatModes, chatModes, postProcessingTasks, selectedRows } = useFileContext(); const isCommunityAllowed = postProcessingTasks.includes('enable_communities'); - const { isGdsActive } = useCredentials(); + const { isGdsActive, userCredentials } = useCredentials(); useEffect(() => { // If rows are selected, the mode is valid (either vector or graph+vector) @@ -43,6 +43,7 @@ export default function ChatModeToggle({ } } }, [selectedRows.length, chatModes.length]); + const memoizedChatModes = useMemo(() => { return isGdsActive && isCommunityAllowed ? AvailableModes diff --git a/frontend/src/components/ChatBot/Communities.tsx b/frontend/src/components/ChatBot/Communities.tsx index e2092c101..11869d3d4 100644 --- a/frontend/src/components/ChatBot/Communities.tsx +++ b/frontend/src/components/ChatBot/Communities.tsx @@ -4,6 +4,7 @@ import ReactMarkdown from 'react-markdown'; import { CommunitiesProps } from '../../types'; const CommunitiesInfo: FC = ({ loading, communities }) => { + console.log('communities', communities); return ( <> {loading ? ( diff --git a/frontend/src/components/ChatBot/CommunitiesInfo.tsx b/frontend/src/components/ChatBot/CommunitiesInfo.tsx new file mode 100644 index 000000000..ad37ceb81 --- /dev/null +++ b/frontend/src/components/ChatBot/CommunitiesInfo.tsx @@ -0,0 +1,40 @@ +import { Box, LoadingSpinner, Flex, Typography } from '@neo4j-ndl/react'; +import { FC } from 'react'; +import ReactMarkdown from 'react-markdown'; +import { CommunitiesProps } from '../../types'; + +const CommunitiesInfo: FC = ({ loading, communities }) => { + return ( + <> + {loading ? ( + + + + ) : communities?.length > 0 ? ( +
    +
      + {communities.map((community, index) => ( +
    • +
      + + ID : + {community.id} + + + Score : + {community.score && {community.score}} + + {community.summary} +
      +
    • + ))} +
    +
    + ) : ( + No Communities Found + )} + + ); +}; + +export default CommunitiesInfo; diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index f74ca7020..641faf6d0 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -18,7 +18,16 @@ import { postProcessing } from '../services/PostProcessing'; import { triggerStatusUpdateAPI } from '../services/ServerSideStatusUpdateAPI'; import useServerSideEvent from '../hooks/useSse'; import { useSearchParams } from 'react-router-dom'; -import { batchSize, buttonCaptions, defaultLLM, largeFileSize, llms, RETRY_OPIONS, tooltips } from '../utils/Constants'; +import { + batchSize, + buttonCaptions, + chatModeLables, + defaultLLM, + largeFileSize, + llms, + RETRY_OPIONS, + tooltips, +} from '../utils/Constants'; import ButtonWithToolTip from './UI/ButtonWithToolTip'; import connectAPI from '../services/ConnectAPI'; import DropdownComponent from './Dropdown'; @@ -96,6 +105,7 @@ const Content: React.FC = ({ queue, processedCount, setProcessedCount, + setchatMode, } = useFileContext(); const [viewPoint, setViewPoint] = useState<'tableView' | 'showGraphView' | 'chatInfoView'>('tableView'); const [showDeletePopUp, setshowDeletePopUp] = useState(false); @@ -542,6 +552,7 @@ const Content: React.FC = ({ setSelectedNodes([]); setSelectedRels([]); setClearHistoryData(true); + setchatMode(chatModeLables.graph_vector_fulltext); }; const retryHandler = async (filename: string, retryoption: string) => { diff --git a/frontend/src/components/FileTable.tsx b/frontend/src/components/FileTable.tsx index 4b6d4bb7e..4ae9cabc4 100644 --- a/frontend/src/components/FileTable.tsx +++ b/frontend/src/components/FileTable.tsx @@ -7,9 +7,11 @@ import { ProgressBar, StatusIndicator, TextLink, + Tip, Typography, + useCopyToClipboard, } from '@neo4j-ndl/react'; -import { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react'; +import { forwardRef, useContext, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react'; import { useReactTable, getCoreRowModel, @@ -35,7 +37,11 @@ import { } from '../utils/Utils'; import { SourceNode, CustomFile, FileTableProps, UserCredentials, statusupdate, ChildRef } from '../types'; import { useCredentials } from '../context/UserCredentials'; -import { ArrowPathIconSolid, MagnifyingGlassCircleIconSolid } from '@neo4j-ndl/react/icons'; +import { + ArrowPathIconSolid, + ClipboardDocumentIconOutline, + MagnifyingGlassCircleIconSolid, +} from '@neo4j-ndl/react/icons'; import CustomProgressBar from './UI/CustomProgressBar'; import subscribe from '../services/PollingAPI'; import { triggerStatusUpdateAPI } from '../services/ServerSideStatusUpdateAPI'; @@ -47,7 +53,9 @@ import { IconButtonWithToolTip } from './UI/IconButtonToolTip'; import { batchSize, largeFileSize, llms } from '../utils/Constants'; import IndeterminateCheckbox from './UI/CustomCheckBox'; import { showErrorToast, showNormalToast } from '../utils/toasts'; +import { ThemeWrapperContext } from '../context/ThemeWrapper'; let onlyfortheFirstRender = true; + const FileTable = forwardRef((props, ref) => { const { isExpanded, connectionStatus, setConnectionStatus, onInspect, onRetry } = props; const { filesData, setFilesData, model, rowSelection, setRowSelection, setSelectedRows, setProcessedCount, queue } = @@ -61,6 +69,8 @@ const FileTable = forwardRef((props, ref) => { const [fileSourceFilter, setFileSourceFilter] = useState(''); const [llmtypeFilter, setLLmtypeFilter] = useState(''); const skipPageResetRef = useRef(false); + const [_, copy] = useCopyToClipboard(); + const { colorMode } = useContext(ThemeWrapperContext); const tableRef = useRef(null); @@ -72,6 +82,10 @@ const FileTable = forwardRef((props, ref) => { showErrorToast(`${fileName} Failed to process`); } ); + + const handleCopy = (message: string) => { + copy(message); + }; const columns = useMemo( () => [ { @@ -140,14 +154,18 @@ const FileTable = forwardRef((props, ref) => { cell: (info) => { if (info.getValue() != 'Processing') { return ( -
    - - {info.getValue()} - {(info.getValue() === 'Completed' || info.getValue() === 'Failed' || info.getValue() === 'Cancelled') && - !isReadOnlyUser && ( + +
    + + + {info.getValue()} + + {(info.getValue() === 'Completed' || + info.getValue() === 'Failed' || + (info.getValue() === 'Cancelled' && !isReadOnlyUser)) && ( ((props, ref) => { )} -
    +
    + + {info.row.original?.status === 'Failed' && ( + + handleCopy(info.row.original?.errorMessage ?? '')} + > + + + + )} + ); } else if (info.getValue() === 'Processing' && info.row.original.processingProgress === undefined) { return ( @@ -510,7 +546,7 @@ const FileTable = forwardRef((props, ref) => { footer: (info) => info.column.id, }), ], - [filesData.length, statusFilter, filetypeFilter, llmtypeFilter, fileSourceFilter, isReadOnlyUser] + [filesData.length, statusFilter, filetypeFilter, llmtypeFilter, fileSourceFilter, isReadOnlyUser, colorMode] ); const table = useReactTable({ diff --git a/frontend/src/components/Layout/SideNav.tsx b/frontend/src/components/Layout/SideNav.tsx index 2472d6e76..12c815757 100644 --- a/frontend/src/components/Layout/SideNav.tsx +++ b/frontend/src/components/Layout/SideNav.tsx @@ -118,7 +118,7 @@ const SideNav: React.FC = ({ + } diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index 3eb3a1fe8..c8c464ead 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -40,7 +40,7 @@ export const chatModeLables = { fulltext: 'fulltext', graph_vector_fulltext: 'graph+vector+fulltext', entity_vector: 'entity search+vector', - unavailableChatMode: 'Chat mode is unavailable when rows are selected', + unavailableChatMode: 'Chat mode is unavailable when files are selected', selected: 'Selected', global_vector: 'global search+vector+fulltext', }; diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index 9a5bec5a8..4aca97286 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -245,6 +245,7 @@ export const filterData = ( nodeIds.has(rel.to) ); filteredScheme = Object.fromEntries(entityTypes.map((key) => [key, scheme[key]])) as Scheme; + console.log('labels', entityNodes); // Only Communities } else if ( graphType.includes('Communities') && @@ -332,6 +333,7 @@ export const filterData = ( filteredNodes = allNodes; filteredRelations = allRelationships; filteredScheme = scheme; + console.log('entity', filteredScheme); } return { filteredNodes, filteredRelations, filteredScheme }; }; From fcb9ab570ce75301412354425021337d6871b225 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Fri, 11 Oct 2024 06:26:18 +0000 Subject: [PATCH 164/292] llm name changes --- frontend/src/utils/Constants.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index c8c464ead..169590c4a 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -12,12 +12,12 @@ export const llms = process.env?.VITE_LLM_MODELS?.trim() != '' ? (process.env.VITE_LLM_MODELS?.split(',') as string[]) : [ - 'diffbot', - 'openai-gpt-3.5', - 'openai-gpt-4o', - 'openai-gpt-4o-mini', - 'gemini-1.5-pro', - 'gemini-1.5-flash', + 'diffbot', + 'openai_gpt_3.5', + 'openai_gpt_4o', + 'openai_gpt_4o_mini', + 'gemini_1.5_pro', + 'gemini_1.5_flash', 'azure_ai_gpt_35', 'azure_ai_gpt_4o', 'ollama_llama3', From f5054888d3db335769ba3af5a9bf185526da5026 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Fri, 11 Oct 2024 06:32:01 +0000 Subject: [PATCH 165/292] build fix --- frontend/src/components/ChatBot/ChatModeToggle.tsx | 2 +- frontend/src/components/Content.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/ChatBot/ChatModeToggle.tsx b/frontend/src/components/ChatBot/ChatModeToggle.tsx index 01e2d1aa7..0317661f6 100644 --- a/frontend/src/components/ChatBot/ChatModeToggle.tsx +++ b/frontend/src/components/ChatBot/ChatModeToggle.tsx @@ -22,7 +22,7 @@ export default function ChatModeToggle({ }) { const { setchatModes, chatModes, postProcessingTasks, selectedRows } = useFileContext(); const isCommunityAllowed = postProcessingTasks.includes('enable_communities'); - const { isGdsActive, userCredentials } = useCredentials(); + const { isGdsActive } = useCredentials(); useEffect(() => { // If rows are selected, the mode is valid (either vector or graph+vector) diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 641faf6d0..95321fc0e 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -105,7 +105,7 @@ const Content: React.FC = ({ queue, processedCount, setProcessedCount, - setchatMode, + setchatModes } = useFileContext(); const [viewPoint, setViewPoint] = useState<'tableView' | 'showGraphView' | 'chatInfoView'>('tableView'); const [showDeletePopUp, setshowDeletePopUp] = useState(false); @@ -552,7 +552,7 @@ const Content: React.FC = ({ setSelectedNodes([]); setSelectedRels([]); setClearHistoryData(true); - setchatMode(chatModeLables.graph_vector_fulltext); + setchatModes([chatModeLables.graph_vector_fulltext]); }; const retryHandler = async (filename: string, retryoption: string) => { From 37de220112e0f40c6139498b143cbd77853e4df1 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Fri, 11 Oct 2024 07:43:39 +0000 Subject: [PATCH 166/292] default mode fix --- frontend/src/utils/Constants.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index 169590c4a..7ca380bac 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -27,10 +27,10 @@ export const llms = 'bedrock_claude_3_5_sonnet', ]; -export const defaultLLM = llms?.includes('openai-gpt-4o') - ? 'openai-gpt-4o' - : llms?.includes('gemini-1.5-pro') - ? 'gemini-1.5-pro' +export const defaultLLM = llms?.includes('openai-gpt_4o') + ? 'openai-gpt_4o' + : llms?.includes('gemini-1.5_pro') + ? 'gemini-1.5_pro' : 'diffbot'; export const chatModeLables = { From a5382262e9608fbe5c67b3588bf887e2471e1a08 Mon Sep 17 00:00:00 2001 From: kaustubh-darekar Date: Fri, 11 Oct 2024 08:14:04 +0000 Subject: [PATCH 167/292] ragas model names update --- backend/score.py | 32 ++++++++------- backend/src/ragas_eval.py | 82 +++++++-------------------------------- 2 files changed, 33 insertions(+), 81 deletions(-) diff --git a/backend/score.py b/backend/score.py index a2ffd033f..22264b635 100644 --- a/backend/score.py +++ b/backend/score.py @@ -712,20 +712,24 @@ async def retry_processing(uri=Form(), userName=Form(), password=Form(), databas gc.collect() @app.post('/metric') -async def calculate_metric(question=Form(),context=Form(),answer=Form(),model=Form()): - try: - result = await asyncio.to_thread(get_ragas_metrics,question,context,answer,model) - if result is None: - return create_api_response('Failed', message='Failed to calculate metrics.',error="Ragas evaluation returned null") - return create_api_response('Success',data=result,message=f"Status set to Reprocess for filename : {result}") - except Exception as e: - job_status = "Failed" - message="Error while calculating evaluation metrics" - error_message = str(e) - logging.exception(f'{error_message}') - return create_api_response(job_status, message=message, error=error_message) - finally: - gc.collect() +async def calculate_metric(question=Form(), context=Form(), answer=Form(), model=Form()): + try: + result = await asyncio.to_thread(get_ragas_metrics, question, context, answer, model) + if result is None or "error" in result: + return create_api_response( + 'Failed', + message='Failed to calculate evaluation metrics.', + error=result.get("error", "Ragas evaluation returned null") + ) + return create_api_response('Success', data=result) + except Exception as e: + job_status = "Failed" + message = "Error while calculating evaluation metrics" + error_message = str(e) + logging.exception(f'{error_message}') + return create_api_response(job_status, message=message, error=error_message) + finally: + gc.collect() if __name__ == "__main__": uvicorn.run(app) diff --git a/backend/src/ragas_eval.py b/backend/src/ragas_eval.py index 940a809dc..e177b6d61 100644 --- a/backend/src/ragas_eval.py +++ b/backend/src/ragas_eval.py @@ -23,19 +23,13 @@ load_dotenv() -# Constants for clarity and maintainability RAGAS_MODEL_VERSIONS = { - "openai-gpt-3.5": "gpt-3.5-turbo-16k", - "gemini-1.0-pro": "gemini-1.0-pro-001", - "gemini-1.5-pro": "gemini-1.5-pro-002", - "gemini-1.5-flash": "gemini-1.5-flash-002", - "openai-gpt-4": "gpt-4-turbo-2024-04-09", - "openai-gpt-4o-mini": "gpt-4o-mini-2024-07-18", - "openai-gpt-4o": "gpt-4o-mini-2024-07-18", - "diffbot": "gpt-4-turbo-2024-04-09", - "groq-llama3": "groq_llama3_70b", + "openai_gpt_3.5": "gpt-3.5-turbo-16k", + "openai_gpt_4": "gpt-4-turbo-2024-04-09", + "openai_gpt_4o_mini": "gpt-4o-mini-2024-07-18", + "openai_gpt_4o": "gpt-4o-mini-2024-07-18", + "groq_llama3_70b": "groq_llama3_70b", } - EMBEDDING_MODEL = os.getenv("EMBEDDING_MODEL") EMBEDDING_FUNCTION, _ = load_embedding_model(EMBEDDING_MODEL) @@ -46,68 +40,16 @@ def get_ragas_llm(model: str) -> Tuple[object, str]: env_value = os.environ.get(env_key) logging.info(f"Loading model configuration: {env_key}") try: - if "gemini" in model: - credentials, project_id = google.auth.default() - model_name = RAGAS_MODEL_VERSIONS[model] - llm = ChatVertexAI( - model_name=model_name, - credentials=credentials, - project=project_id, - temperature=0, - safety_settings={ - #setting safety to NONE for all categories. Consider reviewing this for production systems - HarmCategory.HARM_CATEGORY_UNSPECIFIED: HarmBlockThreshold.BLOCK_NONE, - HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: HarmBlockThreshold.BLOCK_NONE, - HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_NONE, - HarmCategory.HARM_CATEGORY_HARASSMENT: HarmBlockThreshold.BLOCK_NONE, - HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: HarmBlockThreshold.BLOCK_NONE, - }, - ) - elif "openai" in model: + if "openai" in model: model_name = RAGAS_MODEL_VERSIONS[model] llm = ChatOpenAI( api_key=os.environ.get("OPENAI_API_KEY"), model=model_name, temperature=0 ) - - elif "azure" in model: - model_name, api_endpoint, api_key, api_version = env_value.split(",") - llm = AzureChatOpenAI( - api_key=api_key, - azure_endpoint=api_endpoint, - azure_deployment=model_name, - api_version=api_version, - temperature=0, - ) - elif "anthropic" in model: - model_name, api_key = env_value.split(",") - llm = ChatAnthropic(api_key=api_key, model=model_name, temperature=0) - elif "fireworks" in model: - model_name, api_key = env_value.split(",") - llm = ChatFireworks(api_key=api_key, model=model_name) elif "groq" in model: model_name, base_url, api_key = env_value.split(",") llm = ChatGroq(api_key=api_key, model_name=model_name, temperature=0) - elif "bedrock" in model: - model_name, aws_access_key, aws_secret_key, region_name = env_value.split(",") - bedrock_client = boto3.client( - service_name="bedrock-runtime", - region_name=region_name, - aws_access_key_id=aws_access_key, - aws_secret_access_key=aws_secret_key, - ) - llm = ChatBedrock( - client=bedrock_client, model_id=model_name, model_kwargs=dict(temperature=0) - ) - elif "ollama" in model: - model_name, base_url = env_value.split(",") - llm = ChatOllama(base_url=base_url, model=model_name) - elif "diffbot" in model: - llm = DiffbotGraphTransformer( - diffbot_api_key=os.environ.get("DIFFBOT_API_KEY"), - extract_types=["entities", "facts"], - ) else: - raise ValueError(f"Unsupported model: {model}") + raise ValueError(f"Unsupported model for evaluation: {model}") logging.info(f"Model loaded - Model Version: {model}") return llm, model_name @@ -145,6 +87,12 @@ def get_ragas_metrics( end_time = time.time() logging.info(f"Evaluation completed in: {end_time - start_time:.2f} seconds") return score_dict + except ValueError as e: + if "Unsupported model for evaluation" in str(e): + logging.error(f"Unsupported model error: {e}") + return {"error": str(e)} # Return the specific error message as a dictionary + logging.exception(f"ValueError during metrics evaluation: {e}") + return {"error": str(e)} except Exception as e: - logging.exception(f"Error during metrics evaluation: {e}") - return None \ No newline at end of file + logging.exception(f"Error during metrics evaluation: {e}") + return {"error": str(e)} From 784caa6cdafdc7246710a8ae20704632d0fe4925 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Fri, 11 Oct 2024 09:37:01 +0000 Subject: [PATCH 168/292] lint fixes --- .../src/components/ChatBot/ChatInfoModal.tsx | 22 +- .../src/components/ChatBot/ChatModeToggle.tsx | 2 +- frontend/src/components/ChatBot/Chatbot.tsx | 461 +++++++++--------- frontend/src/components/Content.tsx | 2 +- .../Deduplication/index.tsx | 4 +- .../SelectedJobList.tsx | 4 +- frontend/src/utils/Constants.ts | 10 +- frontend/src/utils/Utils.ts | 3 +- 8 files changed, 261 insertions(+), 247 deletions(-) diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index c666d5206..31db9086e 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -71,7 +71,7 @@ const ChatInfoModal: React.FC = ({ const themeUtils = useContext(ThemeWrapperContext); const [, copy] = useCopyToClipboard(); const [copiedText, setcopiedText] = useState(false); - const [showMetricsTable, setShowMetricsTable] = useState(false); + const [showMetricsTable, setShowMetricsTable] = useState(Boolean(metricDetails)); const actions: CypherCodeBlockProps['actions'] = useMemo( () => [ @@ -178,7 +178,7 @@ const ChatInfoModal: React.FC = ({ } () => { setcopiedText(false); - setShowMetricsTable(false); + toggleMetricsLoading(); }; }, [nodeDetails, mode, error]); @@ -263,10 +263,22 @@ const ChatInfoModal: React.FC = ({ detailed scores for this interaction. These scores help us continuously improve the accuracy and helpfulness of our chatbots. + + Faithfulness: Determines How accurately the answer reflects the provided information + + + Answer Relevancy: Determines How well the answer addresses the user's question. + + + Context Utilization: Determines How effectively the system uses the retrieved information to answer the + question. + {showMetricsTable && } - + {!metricDetails && ( + + )} diff --git a/frontend/src/components/ChatBot/ChatModeToggle.tsx b/frontend/src/components/ChatBot/ChatModeToggle.tsx index 0317661f6..df03a1083 100644 --- a/frontend/src/components/ChatBot/ChatModeToggle.tsx +++ b/frontend/src/components/ChatBot/ChatModeToggle.tsx @@ -43,7 +43,7 @@ export default function ChatModeToggle({ } } }, [selectedRows.length, chatModes.length]); - + const memoizedChatModes = useMemo(() => { return isGdsActive && isCommunityAllowed ? AvailableModes diff --git a/frontend/src/components/ChatBot/Chatbot.tsx b/frontend/src/components/ChatBot/Chatbot.tsx index 9e3ba07f6..712286f1a 100644 --- a/frontend/src/components/ChatBot/Chatbot.tsx +++ b/frontend/src/components/ChatBot/Chatbot.tsx @@ -245,7 +245,7 @@ const Chatbot: FC = (props) => { } else { setListMessages((prev) => prev.map((msg) => - msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg + (msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg) ) ); } @@ -260,7 +260,7 @@ const Chatbot: FC = (props) => { } else { setListMessages((prev) => prev.map((msg) => - msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg + (msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg) ) ); } @@ -269,15 +269,15 @@ const Chatbot: FC = (props) => { console.error(`API call failed for mode ${mode}:`, result.reason); setListMessages((prev) => prev.map((msg) => - msg.id === chatbotMessageId + (msg.id === chatbotMessageId ? { - ...msg, - modes: { - ...msg.modes, - [mode]: { message: 'Failed to fetch response for this mode.', error: result.reason }, - }, - } - : msg + ...msg, + modes: { + ...msg.modes, + [mode]: { message: 'Failed to fetch response for this mode.', error: result.reason }, + }, + } + : msg) ) ); } @@ -290,19 +290,19 @@ const Chatbot: FC = (props) => { if (error instanceof Error) { setListMessages((prev) => prev.map((msg) => - msg.id === chatbotMessageId + (msg.id === chatbotMessageId ? { - ...msg, - isLoading: false, - isTyping: false, - modes: { - [chatModes[0]]: { - message: 'An error occurred while processing your request.', - error: error.message, + ...msg, + isLoading: false, + isTyping: false, + modes: { + [chatModes[0]]: { + message: 'An error occurred while processing your request.', + error: error.message, + }, }, - }, - } - : msg + } + : msg) ) ); } @@ -404,105 +404,83 @@ const Chatbot: FC = (props) => { const textFile = new Blob([JSON.stringify(JsonData)], { type: 'application/json' }); if (downloadLinkRef && downloadLinkRef.current) { downloadLinkRef.current.href = URL.createObjectURL(textFile); - downloadLinkRef.current.download = 'data.json'; + downloadLinkRef.current.download = 'graph-builder-chat-details.json'; downloadLinkRef.current.click(); } }, []); -return ( -
    -
    - -
    - {listMessages.map((chat, index) => { - const messagechatModes = Object.keys(chat.modes); - return ( -
    -
    - {chat.user === 'chatbot' ? ( - - ) : ( - - )} -
    - +
    + +
    + {listMessages.map((chat, index) => { + const messagechatModes = Object.keys(chat.modes); + return ( +
    -
    - - {chat.modes[chat.currentMode]?.message || ''} - +
    + {chat.user === 'chatbot' ? ( + + ) : ( + + )}
    -
    -
    - - {chat.datetime} - + +
    + + {chat.modes[chat.currentMode]?.message || ''} +
    - {chat.user === 'chatbot' && - chat.id !== 2 && - !chat.isLoading && - !chat.isTyping && - (!isFullScreen ? ( - 1 ? 'space-between' : 'unset'} - alignItems='center' - > - - {messagechatModes.length > 1 && ( - { - const modes = Object.keys(chat.modes); - const modeswtich = modes[index]; - handleSwitchMode(chat.id, modeswtich); - }} - isFullScreen={false} - currentModeIndex={messagechatModes.indexOf(chat.currentMode)} - modescount={messagechatModes.length} - /> - )} - - ) : ( - - +
    +
    + + {chat.datetime} + +
    + {chat.user === 'chatbot' && + chat.id !== 2 && + !chat.isLoading && + !chat.isTyping && + (!isFullScreen ? ( + 1 ? 'space-between' : 'unset'} + alignItems='center' + > - - {messagechatModes.length > 1 && ( )} - - - ))} -
    -
    -
    - ); - })} -
    - -
    -
    -
    - + ) : ( + + + + + + {messagechatModes.length > 1 && ( + { + const modes = Object.keys(chat.modes); + const modeswtich = modes[index]; + handleSwitchMode(chat.id, modeswtich); + }} + isFullScreen={isFullScreen} + currentModeIndex={messagechatModes.indexOf(chat.currentMode)} + modescount={messagechatModes.length} + /> + )} + + + ))} +
    + +
    + ); + })} +
    +
    +
    +
    + + - + + {buttonCaptions.ask}{' '} + {selectedFileNames != undefined && selectedFileNames.length > 0 && `(${selectedFileNames.length})`} + + +
    + }> + setShowInfoModal(false)} + open={showInfoModal} > - {buttonCaptions.ask}{' '} - {selectedFileNames != undefined && selectedFileNames.length > 0 && `(${selectedFileNames.length})`} - - +
    + { + downloadClickHandler({ + chatResponse: activeChat, + chunks, + metricDetails, + communities, + responseTime, + entities: infoEntities, + nodes, + tokensUsed, + model, + }); + }} + > + + + "" + + + setShowInfoModal(false)} + > + + +
    + +
    +
    - }> - setShowInfoModal(false)} - open={showInfoModal} - > -
    - { - downloadClickHandler({ - chatResponse: activeChat, - chunks, - metricDetails, - communities, - responseTime, - entities: infoEntities, - nodes, - tokensUsed, - model, - }); - }} - > - - - "" - - - setShowInfoModal(false)} - > - - -
    - -
    -
    -
    -); + ); }; export default Chatbot; diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 95321fc0e..3eeace857 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -105,7 +105,7 @@ const Content: React.FC = ({ queue, processedCount, setProcessedCount, - setchatModes + setchatModes, } = useFileContext(); const [viewPoint, setViewPoint] = useState<'tableView' | 'showGraphView' | 'chatInfoView'>('tableView'); const [showDeletePopUp, setshowDeletePopUp] = useState(false); diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx index 36fcff3d1..f5a021e30 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx @@ -80,12 +80,12 @@ export default function DeduplicationTab() { const onRemove = (nodeid: string, similarNodeId: string) => { setDuplicateNodes((prev) => { return prev.map((d) => - d.e.elementId === nodeid + (d.e.elementId === nodeid ? { ...d, similar: d.similar.filter((n) => n.elementId != similarNodeId), } - : d + : d) ); }); }; diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx index a7621f2b6..1cb3c7310 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx @@ -11,11 +11,11 @@ export default function SelectedJobList({ }) { const ongoingPostProcessingTasks = useMemo( () => - isGdsActive + (isGdsActive ? postProcessingTasks.includes('enable_communities') ? postProcessingTasks : postProcessingTasks.filter((s) => s != 'enable_communities') - : postProcessingTasks.filter((s) => s != 'enable_communities'), + : postProcessingTasks.filter((s) => s != 'enable_communities')), [isGdsActive, postProcessingTasks] ); return ( diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index 7ca380bac..1e8c67cef 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -12,7 +12,7 @@ export const llms = process.env?.VITE_LLM_MODELS?.trim() != '' ? (process.env.VITE_LLM_MODELS?.split(',') as string[]) : [ - 'diffbot', + 'diffbot', 'openai_gpt_3.5', 'openai_gpt_4o', 'openai_gpt_4o_mini', @@ -27,10 +27,10 @@ export const llms = 'bedrock_claude_3_5_sonnet', ]; -export const defaultLLM = llms?.includes('openai-gpt_4o') - ? 'openai-gpt_4o' - : llms?.includes('gemini-1.5_pro') - ? 'gemini-1.5_pro' +export const defaultLLM = llms?.includes('openai_gpt_4o') + ? 'openai_gpt_4o' + : llms?.includes('gemini_1.5_pro') + ? 'gemini_1.5_pro' : 'diffbot'; export const chatModeLables = { diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index 4aca97286..d5e2e0f97 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -245,7 +245,6 @@ export const filterData = ( nodeIds.has(rel.to) ); filteredScheme = Object.fromEntries(entityTypes.map((key) => [key, scheme[key]])) as Scheme; - console.log('labels', entityNodes); // Only Communities } else if ( graphType.includes('Communities') && @@ -394,7 +393,7 @@ export const isFileCompleted = (waitingFile: CustomFile, item: SourceNode) => waitingFile && item.status === 'Completed'; export const calculateProcessedCount = (prev: number, batchSize: number) => - prev === batchSize ? batchSize - 1 : prev + 1; + (prev === batchSize ? batchSize - 1 : prev + 1); export const isProcessingFileValid = (item: SourceNode, userCredentials: UserCredentials) => { return item.status === 'Processing' && item.fileName != undefined && userCredentials && userCredentials.database; From b814f71ca1710f6615fc99f22740d2763f6b7333 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Fri, 11 Oct 2024 09:58:36 +0000 Subject: [PATCH 169/292] Chunk Entities API condition --- .../src/components/ChatBot/ChatInfoModal.tsx | 43 ++++++++++++------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index 31db9086e..cfd7e7c2c 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -97,7 +97,10 @@ const ChatInfoModal: React.FC = ({ ); useEffect(() => { - if (mode != chatModeLables.graph || error?.trim() !== '') { + if ( + (mode != chatModeLables.graph || error?.trim() !== '') && + (!nodes.length || !infoEntities.length || !chunks.length) + ) { (async () => { toggleInfoLoading(); try { @@ -258,21 +261,29 @@ const ChatInfoModal: React.FC = ({ - - We use several key metrics to assess the quality of our chat responses. Click the button below to view - detailed scores for this interaction. These scores help us continuously improve the accuracy and - helpfulness of our chatbots. - - - Faithfulness: Determines How accurately the answer reflects the provided information - - - Answer Relevancy: Determines How well the answer addresses the user's question. - - - Context Utilization: Determines How effectively the system uses the retrieved information to answer the - question. - + + + + We use several key metrics to assess the quality of our chat responses. Click the button below to view + detailed scores for this interaction. These scores help us continuously improve the accuracy and + helpfulness of our chatbots. + + + + + Faithfulness: Determines How accurately the answer reflects the + provided information + + + Answer Relevancy: Determines How well the answer addresses the + user's question. + + + Context Utilization: Determines How effectively the system uses the + retrieved information to answer thequestion. + + + {showMetricsTable && } {!metricDetails && ( + )} diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index 1e8c67cef..971227724 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -32,7 +32,7 @@ export const defaultLLM = llms?.includes('openai_gpt_4o') : llms?.includes('gemini_1.5_pro') ? 'gemini_1.5_pro' : 'diffbot'; - +export const supportedLLmsForRagas = ['openai_gpt_3.5', 'openai_gpt_4o', 'openai_gpt_4o_mini', 'groq_llama3_70b']; export const chatModeLables = { vector: 'vector', graph: 'graph', From c5a3dbf722fe5b92d39a6fcf459b707ddc1a1f9b Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Fri, 11 Oct 2024 10:14:45 +0000 Subject: [PATCH 171/292] removed unused imports --- frontend/src/components/ChatBot/ChatInfoModal.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index f151ecc9c..be74580ce 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -8,7 +8,6 @@ import { useCopyToClipboard, Banner, useMediaQuery, - Button, } from '@neo4j-ndl/react'; import { DocumentDuplicateIconOutline, ClipboardDocumentCheckIconOutline } from '@neo4j-ndl/react/icons'; import '../../styling/info.css'; From acdc886b6209ab1fadf2112b1df7bcc1e516c793 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Fri, 11 Oct 2024 10:41:38 +0000 Subject: [PATCH 172/292] multimode fix when we get error response --- frontend/src/components/ChatBot/Chatbot.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/ChatBot/Chatbot.tsx b/frontend/src/components/ChatBot/Chatbot.tsx index 712286f1a..eadd14831 100644 --- a/frontend/src/components/ChatBot/Chatbot.tsx +++ b/frontend/src/components/ChatBot/Chatbot.tsx @@ -232,13 +232,13 @@ const Chatbot: FC = (props) => { total_tokens: response.info.total_tokens, response_time: response.info.response_time, cypher_query: response.info.cypher_query, - graphonly_entities: response.info.context, - entities: response.info.entities, + graphonly_entities: response.info.context??[], + entities: response.info.entities??[], nodeDetails: response.info.nodedetails, error: response.info.error, - metric_question: response.info.metric_details.question, - metric_answer: response.info.metric_details.answer, - metric_contexts: response.info.metric_details.contexts, + metric_question: response.info?.metric_details?.question??'', + metric_answer: response.info?.metric_details?.answer??'', + metric_contexts: response.info?.metric_details?.contexts??'', }; if (index === 0) { simulateTypingEffect(chatbotMessageId, responseMode, mode, responseMode.message); From 2734c4af0cde5f949c65cadd48c9108aa82bb21d Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Fri, 11 Oct 2024 13:40:25 +0000 Subject: [PATCH 173/292] mode changes for score display --- .../src/components/ChatBot/ChatInfoModal.tsx | 10 +++--- frontend/src/components/ChatBot/ChunkInfo.tsx | 33 +++++++++++++------ .../components/ChatBot/CommunitiesInfo.tsx | 9 ++--- frontend/src/types.ts | 2 ++ 4 files changed, 35 insertions(+), 19 deletions(-) diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index c666d5206..d5347eab7 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -234,9 +234,9 @@ const ChatInfoModal: React.FC = ({ {mode != chatModeLables.graph ? Sources used : <>} {mode != chatModeLables.graph ? Chunks : <>} {mode === chatModeLables.graph_vector || - mode === chatModeLables.graph || - mode === chatModeLables.graph_vector_fulltext || - mode === chatModeLables.entity_vector ? ( + mode === chatModeLables.graph || + mode === chatModeLables.graph_vector_fulltext || + mode === chatModeLables.entity_vector ? ( Top Entities used ) : ( <> @@ -278,7 +278,7 @@ const ChatInfoModal: React.FC = ({ /> - + = ({ {mode === chatModeLables.entity_vector || mode === chatModeLables.global_vector ? ( - + ) : ( <> diff --git a/frontend/src/components/ChatBot/ChunkInfo.tsx b/frontend/src/components/ChatBot/ChunkInfo.tsx index 350b41b98..cbb94be21 100644 --- a/frontend/src/components/ChatBot/ChunkInfo.tsx +++ b/frontend/src/components/ChatBot/ChunkInfo.tsx @@ -9,8 +9,9 @@ import s3logo from '../../assets/images/s3logo.png'; import ReactMarkdown from 'react-markdown'; import { generateYouTubeLink, getLogo, isAllowedHost } from '../../utils/Utils'; import { ThemeWrapperContext } from '../../context/ThemeWrapper'; +import { chatModeLables } from '../../utils/Constants'; -const ChunkInfo: FC = ({ loading, chunks }) => { +const ChunkInfo: FC = ({ loading, chunks, mode }) => { const themeUtils = useContext(ThemeWrapperContext); return ( @@ -26,16 +27,18 @@ const ChunkInfo: FC = ({ loading, chunks }) => {
  • {chunk?.page_number ? ( <> -
    - - + + {chunk?.fileName}
    - Similarity Score: {chunk?.score} + {mode !== chatModeLables.global_vector && mode !== chatModeLables.entity_vector && mode !== chatModeLables.graph && ( + Similarity Score: {chunk?.score} + )} ) : chunk?.url && chunk?.start_time ? ( <> @@ -50,7 +53,9 @@ const ChunkInfo: FC = ({ loading, chunks }) => {
  • - Similarity Score: {chunk?.score} + {mode !== chatModeLables.global_vector && mode !== chatModeLables.entity_vector && mode !== chatModeLables.graph && ( + Similarity Score: {chunk?.score} + )} ) : chunk?.url && new URL(chunk.url).host === 'wikipedia.org' ? ( <> @@ -58,7 +63,9 @@ const ChunkInfo: FC = ({ loading, chunks }) => { {chunk?.fileName}
    - Similarity Score: {chunk?.score} + {mode !== chatModeLables.global_vector && mode !== chatModeLables.entity_vector && mode !== chatModeLables.graph && ( + Similarity Score: {chunk?.score} + )} ) : chunk?.url && new URL(chunk.url).host === 'storage.googleapis.com' ? ( <> @@ -66,7 +73,9 @@ const ChunkInfo: FC = ({ loading, chunks }) => { {chunk?.fileName}
    - Similarity Score: {chunk?.score} + {mode !== chatModeLables.global_vector && mode !== chatModeLables.entity_vector && mode !== chatModeLables.graph && ( + Similarity Score: {chunk?.score} + )} ) : chunk?.url && chunk?.url.startsWith('s3://') ? ( <> @@ -74,7 +83,9 @@ const ChunkInfo: FC = ({ loading, chunks }) => { {chunk?.fileName}
    - Similarity Score: {chunk?.score} + {mode !== chatModeLables.global_vector && mode !== chatModeLables.entity_vector && mode !== chatModeLables.graph && ( + Similarity Score: {chunk?.score} + )} ) : chunk?.url && !chunk?.url.startsWith('s3://') && @@ -86,7 +97,9 @@ const ChunkInfo: FC = ({ loading, chunks }) => { {chunk?.url}
    - Similarity Score: {chunk?.score} + {mode !== chatModeLables.global_vector && mode !== chatModeLables.entity_vector && mode !== chatModeLables.graph && ( + Similarity Score: {chunk?.score} + )} ) : ( <> diff --git a/frontend/src/components/ChatBot/CommunitiesInfo.tsx b/frontend/src/components/ChatBot/CommunitiesInfo.tsx index ad37ceb81..ec1017961 100644 --- a/frontend/src/components/ChatBot/CommunitiesInfo.tsx +++ b/frontend/src/components/ChatBot/CommunitiesInfo.tsx @@ -2,8 +2,9 @@ import { Box, LoadingSpinner, Flex, Typography } from '@neo4j-ndl/react'; import { FC } from 'react'; import ReactMarkdown from 'react-markdown'; import { CommunitiesProps } from '../../types'; +import { chatModeLables } from '../../utils/Constants'; -const CommunitiesInfo: FC = ({ loading, communities }) => { +const CommunitiesInfo: FC = ({ loading, communities, mode }) => { return ( <> {loading ? ( @@ -20,10 +21,10 @@ const CommunitiesInfo: FC = ({ loading, communities }) => { ID : {community.id} - + {mode === chatModeLables.global_vector && community.score && ( Score : - {community.score && {community.score}} - + {community.score} + )} {community.summary}
    diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 54deb12b9..d16a61beb 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -698,6 +698,7 @@ export type SourcesProps = { export type ChunkProps = { loading: boolean; chunks: Chunk[]; + mode:string; }; export type EntitiesProps = { @@ -710,6 +711,7 @@ export type EntitiesProps = { export type CommunitiesProps = { loading: boolean; communities: Community[]; + mode:string; }; export interface entity { From a12a6ab776a0f98c0a6d546e76c0f22aa58f9911 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Tue, 15 Oct 2024 06:36:04 +0000 Subject: [PATCH 174/292] fix: Fixed the details state handling between multiple chats feature: Added the warning banner If selected llm model is not supported for raga's evaluation --- .../src/components/ChatBot/ChatInfoModal.tsx | 21 ++++---- frontend/src/components/ChatBot/Chatbot.tsx | 22 +++++--- frontend/src/components/ChatBot/ChunkInfo.tsx | 52 ++++++++++++------- .../components/ChatBot/CommonChatActions.tsx | 6 ++- .../components/ChatBot/CommunitiesInfo.tsx | 10 ++-- .../src/components/Graph/GraphViewModal.tsx | 1 - frontend/src/types.ts | 4 +- 7 files changed, 71 insertions(+), 45 deletions(-) diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index b4fcb77e7..c9d89d11c 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -8,6 +8,7 @@ import { useCopyToClipboard, Banner, useMediaQuery, + Button, } from '@neo4j-ndl/react'; import { DocumentDuplicateIconOutline, ClipboardDocumentCheckIconOutline } from '@neo4j-ndl/react/icons'; import '../../styling/info.css'; @@ -28,7 +29,6 @@ import { Relationship } from '@neo4j-nvl/base'; import { getChatMetrics } from '../../services/GetRagasMetric'; import MetricsTab from './MetricsTab'; import { Stack } from '@mui/material'; -import ButtonWithToolTip from '../UI/ButtonWithToolTip'; const ChatInfoModal: React.FC = ({ sources, @@ -237,9 +237,9 @@ const ChatInfoModal: React.FC = ({ {mode != chatModeLables.graph ? Sources used : <>} {mode != chatModeLables.graph ? Chunks : <>} {mode === chatModeLables.graph_vector || - mode === chatModeLables.graph || - mode === chatModeLables.graph_vector_fulltext || - mode === chatModeLables.entity_vector ? ( + mode === chatModeLables.graph || + mode === chatModeLables.graph_vector_fulltext || + mode === chatModeLables.entity_vector ? ( Top Entities used ) : ( <> @@ -262,11 +262,15 @@ const ChatInfoModal: React.FC = ({ + {!supportedLLmsForRagas.includes(metricmodel) && ( + LLM Model Not Supported ,Please Choose Different Model + )} We use several key metrics to assess the quality of our chat responses. Click the button below to view detailed scores for this interaction. These scores help us continuously improve the accuracy and - helpfulness of our chatbots. + helpfulness of our chatbots.This usually takes about 20 seconds. + You'll see detailed scores shortly. @@ -286,15 +290,14 @@ const ChatInfoModal: React.FC = ({ {showMetricsTable && } {!metricDetails && ( - View Detailed Metrics - + )} @@ -307,7 +310,7 @@ const ChatInfoModal: React.FC = ({ /> - + = (props) => { const [infoLoading, toggleInfoLoading] = useReducer((s) => !s, false); const [metricsLoading, toggleMetricsLoading] = useReducer((s) => !s, false); const downloadLinkRef = useRef(null); - const [activeChat, setActiveChat] = useState(); + const [activeChat, setActiveChat] = useState(null); const [_, copy] = useCopyToClipboard(); const { speak, cancel, speaking } = useSpeechSynthesis({ @@ -232,13 +232,13 @@ const Chatbot: FC = (props) => { total_tokens: response.info.total_tokens, response_time: response.info.response_time, cypher_query: response.info.cypher_query, - graphonly_entities: response.info.context??[], - entities: response.info.entities??[], + graphonly_entities: response.info.context ?? [], + entities: response.info.entities ?? [], nodeDetails: response.info.nodedetails, error: response.info.error, - metric_question: response.info?.metric_details?.question??'', - metric_answer: response.info?.metric_details?.answer??'', - metric_contexts: response.info?.metric_details?.contexts??'', + metric_question: response.info?.metric_details?.question ?? '', + metric_answer: response.info?.metric_details?.answer ?? '', + metric_contexts: response.info?.metric_details?.contexts ?? '', }; if (index === 0) { simulateTypingEffect(chatbotMessageId, responseMode, mode, responseMode.message); @@ -374,7 +374,7 @@ const Chatbot: FC = (props) => { } }; - const detailsHandler = useCallback((chat: Messages) => { + const detailsHandler = useCallback((chat: Messages, previousActiveChat: Messages | null) => { const currentMode = chat.modes[chat.currentMode]; setModelModal(currentMode.model ?? ''); setSourcesModal(currentMode.sources ?? []); @@ -391,6 +391,12 @@ const Chatbot: FC = (props) => { setMetricContext(currentMode.metric_contexts ?? ''); setMetricAnswer(currentMode.metric_answer ?? ''); setActiveChat(chat); + if (previousActiveChat != null && chat.id != previousActiveChat?.id) { + setNodes([]); + setChunks([]); + setInfoEntities([]); + setMetricDetails(null); + } }, []); const speechHandler = useCallback((chat: Messages) => { @@ -487,6 +493,7 @@ const Chatbot: FC = (props) => { detailsHandler={detailsHandler} listMessages={listMessages} speechHandler={speechHandler} + activeChat={activeChat} > {messagechatModes.length > 1 && ( = (props) => { detailsHandler={detailsHandler} listMessages={listMessages} speechHandler={speechHandler} + activeChat={activeChat} >
    diff --git a/frontend/src/components/ChatBot/ChunkInfo.tsx b/frontend/src/components/ChatBot/ChunkInfo.tsx index cbb94be21..05fa229a1 100644 --- a/frontend/src/components/ChatBot/ChunkInfo.tsx +++ b/frontend/src/components/ChatBot/ChunkInfo.tsx @@ -28,17 +28,19 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { {chunk?.page_number ? ( <>
    - - + {chunk?.fileName}
    - {mode !== chatModeLables.global_vector && mode !== chatModeLables.entity_vector && mode !== chatModeLables.graph && ( - Similarity Score: {chunk?.score} - )} + {mode !== chatModeLables.global_vector && + mode !== chatModeLables.entity_vector && + mode !== chatModeLables.graph && ( + Similarity Score: {chunk?.score} + )} ) : chunk?.url && chunk?.start_time ? ( <> @@ -53,9 +55,11 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => {
    - {mode !== chatModeLables.global_vector && mode !== chatModeLables.entity_vector && mode !== chatModeLables.graph && ( - Similarity Score: {chunk?.score} - )} + {mode !== chatModeLables.global_vector && + mode !== chatModeLables.entity_vector && + mode !== chatModeLables.graph && ( + Similarity Score: {chunk?.score} + )} ) : chunk?.url && new URL(chunk.url).host === 'wikipedia.org' ? ( <> @@ -63,9 +67,11 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { {chunk?.fileName}
    - {mode !== chatModeLables.global_vector && mode !== chatModeLables.entity_vector && mode !== chatModeLables.graph && ( - Similarity Score: {chunk?.score} - )} + {mode !== chatModeLables.global_vector && + mode !== chatModeLables.entity_vector && + mode !== chatModeLables.graph && ( + Similarity Score: {chunk?.score} + )} ) : chunk?.url && new URL(chunk.url).host === 'storage.googleapis.com' ? ( <> @@ -73,9 +79,11 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { {chunk?.fileName}
    - {mode !== chatModeLables.global_vector && mode !== chatModeLables.entity_vector && mode !== chatModeLables.graph && ( - Similarity Score: {chunk?.score} - )} + {mode !== chatModeLables.global_vector && + mode !== chatModeLables.entity_vector && + mode !== chatModeLables.graph && ( + Similarity Score: {chunk?.score} + )} ) : chunk?.url && chunk?.url.startsWith('s3://') ? ( <> @@ -83,9 +91,11 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { {chunk?.fileName}
    - {mode !== chatModeLables.global_vector && mode !== chatModeLables.entity_vector && mode !== chatModeLables.graph && ( - Similarity Score: {chunk?.score} - )} + {mode !== chatModeLables.global_vector && + mode !== chatModeLables.entity_vector && + mode !== chatModeLables.graph && ( + Similarity Score: {chunk?.score} + )} ) : chunk?.url && !chunk?.url.startsWith('s3://') && @@ -97,9 +107,11 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { {chunk?.url}
    - {mode !== chatModeLables.global_vector && mode !== chatModeLables.entity_vector && mode !== chatModeLables.graph && ( - Similarity Score: {chunk?.score} - )} + {mode !== chatModeLables.global_vector && + mode !== chatModeLables.entity_vector && + mode !== chatModeLables.graph && ( + Similarity Score: {chunk?.score} + )} ) : ( <> diff --git a/frontend/src/components/ChatBot/CommonChatActions.tsx b/frontend/src/components/ChatBot/CommonChatActions.tsx index 07f04bc8f..80d904f6a 100644 --- a/frontend/src/components/ChatBot/CommonChatActions.tsx +++ b/frontend/src/components/ChatBot/CommonChatActions.tsx @@ -10,9 +10,11 @@ export default function CommonActions({ speechHandler, copyHandler, listMessages, + activeChat, }: { chat: Messages; - detailsHandler: (chat: Messages) => void; + activeChat: Messages | null; + detailsHandler: (chat: Messages, activeChat: Messages | null) => void; speechHandler: (chat: Messages) => void; copyHandler: (message: string, id: number) => void; listMessages: Messages[]; @@ -27,7 +29,7 @@ export default function CommonActions({ text='Retrieval Information' label='Retrieval Information' disabled={chat.isTyping || chat.isLoading} - onClick={() => detailsHandler(chat)} + onClick={() => detailsHandler(chat, activeChat)} > {buttonCaptions.details} diff --git a/frontend/src/components/ChatBot/CommunitiesInfo.tsx b/frontend/src/components/ChatBot/CommunitiesInfo.tsx index ec1017961..088e4e370 100644 --- a/frontend/src/components/ChatBot/CommunitiesInfo.tsx +++ b/frontend/src/components/ChatBot/CommunitiesInfo.tsx @@ -21,10 +21,12 @@ const CommunitiesInfo: FC = ({ loading, communities, mode }) = ID : {community.id} - {mode === chatModeLables.global_vector && community.score && ( - Score : - {community.score} - )} + {mode === chatModeLables.global_vector && community.score && ( + + Score : + {community.score} + + )} {community.summary}
    diff --git a/frontend/src/components/Graph/GraphViewModal.tsx b/frontend/src/components/Graph/GraphViewModal.tsx index dddfb4175..33a46c1c1 100644 --- a/frontend/src/components/Graph/GraphViewModal.tsx +++ b/frontend/src/components/Graph/GraphViewModal.tsx @@ -74,7 +74,6 @@ const GraphViewModal: React.FunctionComponent = ({ {} ); }; - console.log('graphType', graphType); // Unmounting the component useEffect(() => { const timeoutId = setTimeout(() => { diff --git a/frontend/src/types.ts b/frontend/src/types.ts index d16a61beb..0f8f913d3 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -698,7 +698,7 @@ export type SourcesProps = { export type ChunkProps = { loading: boolean; chunks: Chunk[]; - mode:string; + mode: string; }; export type EntitiesProps = { @@ -711,7 +711,7 @@ export type EntitiesProps = { export type CommunitiesProps = { loading: boolean; communities: Community[]; - mode:string; + mode: string; }; export interface entity { From ba091a0f9ecd370b2f1864ed401b330ea26e5171 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Tue, 15 Oct 2024 07:23:33 +0000 Subject: [PATCH 175/292] Fix: Entity Mode Width Fix --- frontend/src/components/ChatBot/Chatbot.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frontend/src/components/ChatBot/Chatbot.tsx b/frontend/src/components/ChatBot/Chatbot.tsx index 14e2daffe..b3a122433 100644 --- a/frontend/src/components/ChatBot/Chatbot.tsx +++ b/frontend/src/components/ChatBot/Chatbot.tsx @@ -406,6 +406,7 @@ const Chatbot: FC = (props) => { handleSpeak(chat.modes[chat.currentMode]?.message, chat.id); } }, []); + const downloadClickHandler = useCallback(function downloadClickHandler(JsonData: Type) { const textFile = new Blob([JSON.stringify(JsonData)], { type: 'application/json' }); if (downloadLinkRef && downloadLinkRef.current) { @@ -580,6 +581,7 @@ const Chatbot: FC = (props) => { }} onClose={() => setShowInfoModal(false)} open={showInfoModal} + size={activeChat?.currentMode === chatModeLables.entity_vector ? 'large' : 'medium'} >
    Date: Tue, 15 Oct 2024 14:07:40 +0530 Subject: [PATCH 176/292] diffbot fix for async (#797) --- backend/src/llm.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/backend/src/llm.py b/backend/src/llm.py index f43be2a67..93ee0f08f 100644 --- a/backend/src/llm.py +++ b/backend/src/llm.py @@ -150,7 +150,6 @@ async def get_graph_document_list( ): futures = [] graph_document_list = [] - if "diffbot_api_key" in dir(llm): llm_transformer = llm else: @@ -181,7 +180,11 @@ async def get_graph_document_list( # for i, future in enumerate(concurrent.futures.as_completed(futures)): # graph_document = future.result() # graph_document_list.append(graph_document[0]) - graph_document_list = await llm_transformer.aconvert_to_graph_documents(combined_chunk_document_list) + + if isinstance(llm,DiffbotGraphTransformer): + graph_document_list = llm_transformer.convert_to_graph_documents(combined_chunk_document_list) + else: + graph_document_list = await llm_transformer.aconvert_to_graph_documents(combined_chunk_document_list) return graph_document_list From 821b0f438734dc61f55d001988cec6ab07003de4 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Tue, 15 Oct 2024 14:43:27 +0530 Subject: [PATCH 177/292] Minor changes (#798) * added congig variable for default diffbot chat model * fulltext index creation is skipped when the labels are empty * entity vector change * added optinal to communities for entity mode * updated the entity query --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> --- backend/src/QA_integration.py | 3 ++- backend/src/post_processing.py | 9 ++++++--- backend/src/shared/constants.py | 4 ++-- frontend/src/components/ChatBot/ChatModeToggle.tsx | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/backend/src/QA_integration.py b/backend/src/QA_integration.py index 30375a9d9..cf7c74f6d 100644 --- a/backend/src/QA_integration.py +++ b/backend/src/QA_integration.py @@ -402,7 +402,8 @@ def get_neo4j_retriever(graph, document_names,chat_mode_settings, score_threshol def setup_chat(model, graph, document_names, chat_mode_settings): start_time = time.time() try: - model = "openai-gpt-4o" if model == "diffbot" else model + if model == "diffbot": + model = os.getenv('DEFAULT_DIFFBOT_CHAT_MODEL') llm, model_name = get_llm(model=model) logging.info(f"Model called in chat: {model} (version: {model_name})") diff --git a/backend/src/post_processing.py b/backend/src/post_processing.py index 22af50b76..7746df3d0 100644 --- a/backend/src/post_processing.py +++ b/backend/src/post_processing.py @@ -93,9 +93,12 @@ def create_fulltext(driver,type): for label in FILTER_LABELS: if label in labels: labels.remove(label) - - labels_str = ":" + "|".join([f"`{label}`" for label in labels]) - logging.info(f"Fetched labels in {time.time() - start_step:.2f} seconds.") + if labels: + labels_str = ":" + "|".join([f"`{label}`" for label in labels]) + logging.info(f"Fetched labels in {time.time() - start_step:.2f} seconds.") + else: + logging.info("Full text index is not created as labels are empty") + return except Exception as e: logging.error(f"Failed to fetch labels: {e}") return diff --git a/backend/src/shared/constants.py b/backend/src/shared/constants.py index 20bbffa3f..33b27b20a 100644 --- a/backend/src/shared/constants.py +++ b/backend/src/shared/constants.py @@ -382,7 +382,7 @@ collect {{ UNWIND nodes AS n - MATCH (n)-[:IN_COMMUNITY]->(c:__Community__) + OPTIONAL MATCH (n)-[:IN_COMMUNITY]->(c:__Community__) WITH c, c.community_rank AS rank, c.weight AS weight RETURN c ORDER BY rank, weight DESC @@ -477,7 +477,7 @@ } ] AS chunks, [ - community IN communities | + community IN communities WHERE community IS NOT NULL | community { .*, embedding: null diff --git a/frontend/src/components/ChatBot/ChatModeToggle.tsx b/frontend/src/components/ChatBot/ChatModeToggle.tsx index df03a1083..cd7b4b796 100644 --- a/frontend/src/components/ChatBot/ChatModeToggle.tsx +++ b/frontend/src/components/ChatBot/ChatModeToggle.tsx @@ -48,7 +48,7 @@ export default function ChatModeToggle({ return isGdsActive && isCommunityAllowed ? AvailableModes : AvailableModes?.filter( - (m) => !m.mode.includes(chatModeLables.entity_vector) && !m.mode.includes(chatModeLables.global_vector) + (m) => !m.mode.includes(chatModeLables.global_vector) ); }, [isGdsActive, isCommunityAllowed]); const menuItems = useMemo(() => { From 702ebf761673eab390be85747731d49a2f914858 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Tue, 15 Oct 2024 09:32:19 +0000 Subject: [PATCH 178/292] New: Added the supported llm models for ragas evaluation --- .../src/components/ChatBot/ChatInfoModal.tsx | 23 +++++++++++++++---- frontend/src/components/ChatBot/Chatbot.tsx | 2 +- frontend/src/components/Dropdown.tsx | 11 ++------- frontend/src/components/FileTable.tsx | 13 ++--------- frontend/src/utils/Utils.ts | 1 + 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index c9d89d11c..7401f0fa5 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -29,6 +29,7 @@ import { Relationship } from '@neo4j-nvl/base'; import { getChatMetrics } from '../../services/GetRagasMetric'; import MetricsTab from './MetricsTab'; import { Stack } from '@mui/material'; +import { capitalizeWithUnderscore } from '../../utils/Utils'; const ChatInfoModal: React.FC = ({ sources, @@ -263,14 +264,28 @@ const ChatInfoModal: React.FC = ({ {!supportedLLmsForRagas.includes(metricmodel) && ( - LLM Model Not Supported ,Please Choose Different Model + + Currently ragas evaluation works on{' '} + {supportedLLmsForRagas.map((s, idx) => ( + + {capitalizeWithUnderscore(s) + (idx != supportedLLmsForRagas.length - 1 ? ',' : '')} + + ))} + . + + } + > )} We use several key metrics to assess the quality of our chat responses. Click the button below to view - detailed scores for this interaction. These scores help us continuously improve the accuracy and - helpfulness of our chatbots.This usually takes about 20 seconds. - You'll see detailed scores shortly. + detailed scores for this interaction using ragas framework. These + scores help us continuously improve the accuracy and helpfulness of our chatbots.This usually takes + about 20 seconds . You'll see detailed scores shortly. diff --git a/frontend/src/components/ChatBot/Chatbot.tsx b/frontend/src/components/ChatBot/Chatbot.tsx index b3a122433..bb50cd54f 100644 --- a/frontend/src/components/ChatBot/Chatbot.tsx +++ b/frontend/src/components/ChatBot/Chatbot.tsx @@ -406,7 +406,7 @@ const Chatbot: FC = (props) => { handleSpeak(chat.modes[chat.currentMode]?.message, chat.id); } }, []); - + const downloadClickHandler = useCallback(function downloadClickHandler(JsonData: Type) { const textFile = new Blob([JSON.stringify(JsonData)], { type: 'application/json' }); if (downloadLinkRef && downloadLinkRef.current) { diff --git a/frontend/src/components/Dropdown.tsx b/frontend/src/components/Dropdown.tsx index cdf658824..48188f38b 100644 --- a/frontend/src/components/Dropdown.tsx +++ b/frontend/src/components/Dropdown.tsx @@ -1,7 +1,7 @@ import { Dropdown, Tip } from '@neo4j-ndl/react'; import { OptionType, ReusableDropdownProps } from '../types'; import { memo, useMemo, useReducer } from 'react'; -import { capitalize } from '../utils/Utils'; +import { capitalize, capitalizeWithUnderscore } from '../utils/Utils'; const DropdownComponent: React.FC = ({ options, @@ -31,14 +31,7 @@ const DropdownComponent: React.FC = ({ onChange: handleChange, options: allOptions?.map((option) => { const label = - typeof option === 'string' - ? (option.includes('LLM_MODEL_CONFIG_') - ? capitalize(option.split('LLM_MODEL_CONFIG_').at(-1) as string) - : capitalize(option) - ) - .split('_') - .join(' ') - : capitalize(option.label); + typeof option === 'string' ? capitalizeWithUnderscore(option) : capitalize(option.label); const value = typeof option === 'string' ? option : option.value; return { label, diff --git a/frontend/src/components/FileTable.tsx b/frontend/src/components/FileTable.tsx index 4ae9cabc4..e5aa5ada4 100644 --- a/frontend/src/components/FileTable.tsx +++ b/frontend/src/components/FileTable.tsx @@ -29,11 +29,11 @@ import { getSourceNodes } from '../services/GetFiles'; import { v4 as uuidv4 } from 'uuid'; import { statusCheck, - capitalize, isFileCompleted, calculateProcessedCount, getFileSourceStatus, isProcessingFileValid, + capitalizeWithUnderscore, } from '../utils/Utils'; import { SourceNode, CustomFile, FileTableProps, UserCredentials, statusupdate, ChildRef } from '../types'; import { useCredentials } from '../context/UserCredentials'; @@ -467,16 +467,7 @@ const FileTable = forwardRef((props, ref) => { id: 'model', cell: (info) => { const model = info.getValue(); - return ( - - {(model.includes('LLM_MODEL_CONFIG_') - ? capitalize(model.split('LLM_MODEL_CONFIG_').at(-1) as string) - : capitalize(model) - ) - .split('_') - .join(' ')} - - ); + return {capitalizeWithUnderscore(model)}; }, header: () => Model, footer: (info) => info.column.id, diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index d5e2e0f97..4b0ad5e0e 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -410,6 +410,7 @@ export const capitalizeWithPlus = (s: string) => { .map((s) => capitalize(s)) .join('+'); }; +export const capitalizeWithUnderscore = (s: string) => capitalize(s).split('_').join(' '); export const getDescriptionForChatMode = (mode: string): string => { switch (mode.toLowerCase()) { From dcb39757c8c4b62e3e24c000564786192db27099 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Tue, 15 Oct 2024 09:45:03 +0000 Subject: [PATCH 179/292] Fix: Communitites Tab is displayed based communitites length --- frontend/src/components/ChatBot/ChatInfoModal.tsx | 6 +++++- frontend/src/components/ChatBot/ChatModeToggle.tsx | 4 +--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index 7401f0fa5..7fb819a32 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -250,7 +250,11 @@ const ChatInfoModal: React.FC = ({ ) : ( <> )} - {mode === chatModeLables.entity_vector ? Communities : <>} + {mode === chatModeLables.entity_vector && communities.length ? ( + Communities + ) : ( + <> + )} Evaluation Metrics )} diff --git a/frontend/src/components/ChatBot/ChatModeToggle.tsx b/frontend/src/components/ChatBot/ChatModeToggle.tsx index cd7b4b796..d7ce7a3bf 100644 --- a/frontend/src/components/ChatBot/ChatModeToggle.tsx +++ b/frontend/src/components/ChatBot/ChatModeToggle.tsx @@ -47,9 +47,7 @@ export default function ChatModeToggle({ const memoizedChatModes = useMemo(() => { return isGdsActive && isCommunityAllowed ? AvailableModes - : AvailableModes?.filter( - (m) => !m.mode.includes(chatModeLables.global_vector) - ); + : AvailableModes?.filter((m) => !m.mode.includes(chatModeLables.global_vector)); }, [isGdsActive, isCommunityAllowed]); const menuItems = useMemo(() => { return memoizedChatModes?.map((m) => { From d3e53659a4977633e48d7e0f4f1ad9d02033c9cf Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Tue, 15 Oct 2024 16:55:11 +0530 Subject: [PATCH 180/292] added the conversation download button (#800) --- frontend/src/components/ChatBot/Chatbot.tsx | 37 +++++++++------------ frontend/src/components/Layout/SideNav.tsx | 33 ++++++++++++++++-- frontend/src/utils/Utils.ts | 12 +++++++ 3 files changed, 58 insertions(+), 24 deletions(-) diff --git a/frontend/src/components/ChatBot/Chatbot.tsx b/frontend/src/components/ChatBot/Chatbot.tsx index bb50cd54f..9cc426d12 100644 --- a/frontend/src/components/ChatBot/Chatbot.tsx +++ b/frontend/src/components/ChatBot/Chatbot.tsx @@ -37,7 +37,7 @@ import { buttonCaptions, chatModeLables } from '../../utils/Constants'; import useSpeechSynthesis from '../../hooks/useSpeech'; import ButtonWithToolTip from '../UI/ButtonWithToolTip'; import FallBackDialog from '../UI/FallBackDialog'; -import { getDateTime } from '../../utils/Utils'; +import { downloadClickHandler, getDateTime } from '../../utils/Utils'; import ChatModesSwitch from './ChatModesSwitch'; import CommonActions from './CommonChatActions'; const InfoModal = lazy(() => import('./ChatInfoModal')); @@ -407,15 +407,6 @@ const Chatbot: FC = (props) => { } }, []); - const downloadClickHandler = useCallback(function downloadClickHandler(JsonData: Type) { - const textFile = new Blob([JSON.stringify(JsonData)], { type: 'application/json' }); - if (downloadLinkRef && downloadLinkRef.current) { - downloadLinkRef.current.href = URL.createObjectURL(textFile); - downloadLinkRef.current.download = 'graph-builder-chat-details.json'; - downloadLinkRef.current.click(); - } - }, []); - return (
    @@ -590,17 +581,21 @@ const Chatbot: FC = (props) => { clean disabled={metricsLoading || infoLoading} onClick={() => { - downloadClickHandler({ - chatResponse: activeChat, - chunks, - metricDetails, - communities, - responseTime, - entities: infoEntities, - nodes, - tokensUsed, - model, - }); + downloadClickHandler( + { + chatResponse: activeChat, + chunks, + metricDetails, + communities, + responseTime, + entities: infoEntities, + nodes, + tokensUsed, + model, + }, + downloadLinkRef, + 'graph-builder-chat-details.json' + ); }} > diff --git a/frontend/src/components/Layout/SideNav.tsx b/frontend/src/components/Layout/SideNav.tsx index 12c815757..e09ac434a 100644 --- a/frontend/src/components/Layout/SideNav.tsx +++ b/frontend/src/components/Layout/SideNav.tsx @@ -1,5 +1,5 @@ -import React, { useEffect, useState } from 'react'; -import { Dialog, SideNavigation, Tip, useMediaQuery } from '@neo4j-ndl/react'; +import React, { useEffect, useRef, useState } from 'react'; +import { Dialog, SideNavigation, TextLink, Tip, useMediaQuery } from '@neo4j-ndl/react'; import { ArrowRightIconOutline, ArrowLeftIconOutline, @@ -7,12 +7,13 @@ import { ArrowsPointingOutIconOutline, ChatBubbleOvalLeftEllipsisIconOutline, CloudArrowUpIconSolid, + ArrowDownTrayIconOutline, } from '@neo4j-ndl/react/icons'; import { SideNavProps } from '../../types'; import Chatbot from '../ChatBot/Chatbot'; import { createPortal } from 'react-dom'; import { useMessageContext } from '../../context/UserMessages'; -import { getIsLoading } from '../../utils/Utils'; +import { downloadClickHandler, getIsLoading } from '../../utils/Utils'; import ExpandedChatButtonContainer from '../ChatBot/ExpandedChatButtonContainer'; import { APP_SOURCES, tooltips } from '../../utils/Constants'; import ChatModeToggle from '../ChatBot/ChatModeToggle'; @@ -46,6 +47,7 @@ const SideNav: React.FC = ({ const [showChatMode, setshowChatMode] = useState(false); const largedesktops = useMediaQuery(`(min-width:1440px )`); const { connectionStatus, isReadOnlyUser } = useCredentials(); + const downloadLinkRef = useRef(null); const date = new Date(); useEffect(() => { @@ -93,6 +95,7 @@ const SideNav: React.FC = ({ toggleDrawer(); } }; + return (
    @@ -189,6 +192,30 @@ const SideNav: React.FC = ({ } /> + + { + downloadClickHandler( + { conversation: messages }, + downloadLinkRef, + 'graph-builder-conversation.json' + ); + }} + icon={ + <> + + + + + Download Conversation + + "" + + + + } + /> + {!isChatModalOpen && ( { diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index 4b0ad5e0e..27645ac7e 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -497,3 +497,15 @@ export const graphTypeFromNodes = (allNodes: ExtendedNode[]) => { } return graphType; }; +export function downloadClickHandler( + JsonData: Type, + downloadLinkRef: React.RefObject, + filename: string +) { + const textFile = new Blob([JSON.stringify(JsonData)], { type: 'application/json' }); + if (downloadLinkRef && downloadLinkRef.current) { + downloadLinkRef.current.href = URL.createObjectURL(textFile); + downloadLinkRef.current.download = filename; + downloadLinkRef.current.click(); + } +} From 0ff8bd11a7df50d6fd918fef96d2b93a300d5dcc Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Tue, 15 Oct 2024 13:56:09 +0000 Subject: [PATCH 181/292] model name correction --- backend/score.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/score.py b/backend/score.py index 22264b635..80eb3a7c2 100644 --- a/backend/score.py +++ b/backend/score.py @@ -276,7 +276,7 @@ async def post_processing(uri=Form(), userName=Form(), password=Form(), database logging.info(f'Entity Embeddings created') if "enable_communities" in tasks: - model = "openai-gpt-4o" + model = "openai_gpt_4o" await asyncio.to_thread(create_communities, uri, userName, password, database,model) josn_obj = {'api_name': 'post_processing/create_communities', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} logger.log_struct(josn_obj) From 09ea0717bb28ded897191ff347574fb453cf9947 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Thu, 17 Oct 2024 11:49:28 +0000 Subject: [PATCH 182/292] chatmode switch mode fix --- frontend/src/components/ChatBot/Chatbot.tsx | 61 ++++++++++----------- 1 file changed, 29 insertions(+), 32 deletions(-) diff --git a/frontend/src/components/ChatBot/Chatbot.tsx b/frontend/src/components/ChatBot/Chatbot.tsx index 9cc426d12..a1eeb35ef 100644 --- a/frontend/src/components/ChatBot/Chatbot.tsx +++ b/frontend/src/components/ChatBot/Chatbot.tsx @@ -269,15 +269,15 @@ const Chatbot: FC = (props) => { console.error(`API call failed for mode ${mode}:`, result.reason); setListMessages((prev) => prev.map((msg) => - (msg.id === chatbotMessageId - ? { - ...msg, - modes: { - ...msg.modes, - [mode]: { message: 'Failed to fetch response for this mode.', error: result.reason }, - }, - } - : msg) + (msg.id === chatbotMessageId + ? { + ...msg, + modes: { + ...msg.modes, + [mode]: { message: 'Failed to fetch response for this mode.', error: result.reason }, + }, + } + : msg) ) ); } @@ -290,19 +290,19 @@ const Chatbot: FC = (props) => { if (error instanceof Error) { setListMessages((prev) => prev.map((msg) => - (msg.id === chatbotMessageId - ? { - ...msg, - isLoading: false, - isTyping: false, - modes: { - [chatModes[0]]: { - message: 'An error occurred while processing your request.', - error: error.message, - }, - }, - } - : msg) + (msg.id === chatbotMessageId + ? { + ...msg, + isLoading: false, + isTyping: false, + modes: { + [chatModes[0]]: { + message: 'An error occurred while processing your request.', + error: error.message, + }, + }, + } + : msg) ) ); } @@ -391,7 +391,7 @@ const Chatbot: FC = (props) => { setMetricContext(currentMode.metric_contexts ?? ''); setMetricAnswer(currentMode.metric_answer ?? ''); setActiveChat(chat); - if (previousActiveChat != null && chat.id != previousActiveChat?.id) { + if ((previousActiveChat != null && chat.id != previousActiveChat?.id) || (previousActiveChat != null && chat.currentMode != previousActiveChat.currentMode)) { setNodes([]); setChunks([]); setInfoEntities([]); @@ -450,14 +450,12 @@ const Chatbot: FC = (props) => {
    {chat.modes[chat.currentMode]?.message || ''} @@ -541,9 +539,8 @@ const Chatbot: FC = (props) => {
    Date: Fri, 18 Oct 2024 15:36:58 +0530 Subject: [PATCH 183/292] Add API payload GCP logging (#805) --- backend/score.py | 79 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 68 insertions(+), 11 deletions(-) diff --git a/backend/score.py b/backend/score.py index 80eb3a7c2..1efd46f86 100644 --- a/backend/score.py +++ b/backend/score.py @@ -93,6 +93,10 @@ async def create_source_knowledge_graph_url( try: start = time.time() + payload_json_obj = {'api_name':'url_scan', 'db_url':uri, 'userName':userName, 'database':database, 'source_url':source_url, 'aws_access_key_id':aws_access_key_id, + 'model':model, 'gcs_bucket_name':gcs_bucket_name, 'gcs_bucket_folder':gcs_bucket_folder, 'source_type':source_type, + 'gcs_project_id':gcs_project_id, 'wiki_query':wiki_query, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(payload_json_obj, "INFO") if source_url is not None: source = source_url else: @@ -174,6 +178,11 @@ async def extract_knowledge_graph_from_file( """ try: start_time = time.time() + payload_json_obj = {'api_name':'extract', 'db_url':uri, 'userName':userName, 'database':database, 'source_url':source_url, 'aws_access_key_id':aws_access_key_id, + 'model':model, 'gcs_bucket_name':gcs_bucket_name, 'gcs_bucket_folder':gcs_bucket_folder, 'source_type':source_type,'gcs_blob_filename':gcs_blob_filename, + 'file_name':file_name, 'gcs_project_id':gcs_project_id, 'wiki_query':wiki_query,'allowedNodes':allowedNodes,'allowedRelationship':allowedRelationship, + 'language':language ,'retry_condition':retry_condition,'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(payload_json_obj, "INFO") graph = create_graph_database_connection(uri, userName, password, database) graphDb_data_Access = graphDBdataAccess(graph) @@ -238,6 +247,8 @@ async def get_source_list(uri:str, userName:str, password:str, database:str=None """ try: start = time.time() + payload_json_obj = {'api_name':'sources_list', 'db_url':uri, 'userName':userName, 'database':database, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(payload_json_obj, "INFO") decoded_password = decode_password(password) if " " in uri: uri = uri.replace(" ","+") @@ -257,6 +268,8 @@ async def get_source_list(uri:str, userName:str, password:str, database:str=None @app.post("/post_processing") async def post_processing(uri=Form(), userName=Form(), password=Form(), database=Form(), tasks=Form(None)): try: + payload_json_obj = {'api_name':'post_processing', 'db_url':uri, 'userName':userName, 'database':database, 'tasks':tasks, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(payload_json_obj, "INFO") graph = create_graph_database_connection(uri, userName, password, database) tasks = set(map(str.strip, json.loads(tasks))) @@ -279,8 +292,9 @@ async def post_processing(uri=Form(), userName=Form(), password=Form(), database model = "openai_gpt_4o" await asyncio.to_thread(create_communities, uri, userName, password, database,model) josn_obj = {'api_name': 'post_processing/create_communities', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(josn_obj) logging.info(f'created communities') + + logger.log_struct(josn_obj) return create_api_response('Success', message='All tasks completed successfully') except Exception as e: @@ -298,6 +312,9 @@ async def chat_bot(uri=Form(),model=Form(None),userName=Form(), password=Form(), logging.info(f"QA_RAG called at {datetime.now()}") qa_rag_start_time = time.time() try: + payload_json_obj = {'api_name':'chat_bot', 'db_url':uri, 'userName':userName, 'database':database, 'question':question,'document_names':document_names, + 'session_id':session_id, 'mode':mode, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(payload_json_obj, "INFO") if mode == "graph": graph = Neo4jGraph( url=uri,username=userName,password=password,database=database,sanitize = True, refresh_schema=True) else: @@ -311,7 +328,7 @@ async def chat_bot(uri=Form(),model=Form(None),userName=Form(), password=Form(), logging.info(f"Total Response time is {total_call_time:.2f} seconds") result["info"]["response_time"] = round(total_call_time, 2) - json_obj = {'api_name':'chat_bot','db_url':uri,'session_id':session_id, 'logging_time': formatted_time(datetime.now(timezone.utc)), 'elapsed_api_time':f'{total_call_time:.2f}'} + json_obj = {'api_name':'chat_bot','db_url':uri,'session_id':session_id,'mode':mode, 'logging_time': formatted_time(datetime.now(timezone.utc)), 'elapsed_api_time':f'{total_call_time:.2f}'} logger.log_struct(json_obj, "INFO") return create_api_response('Success',data=result) @@ -328,6 +345,9 @@ async def chat_bot(uri=Form(),model=Form(None),userName=Form(), password=Form(), async def chunk_entities(uri=Form(),userName=Form(), password=Form(), database=Form(), nodedetails=Form(None),entities=Form(),mode=Form()): try: start = time.time() + payload_json_obj = {'api_name':'chunk_entities', 'db_url':uri, 'userName':userName, 'database':database, 'nodedetails':nodedetails,'entities':entities, + 'mode':mode, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(payload_json_obj, "INFO") result = await asyncio.to_thread(get_entities_from_chunkids,uri=uri, username=userName, password=password, database=database,nodedetails=nodedetails,entities=entities,mode=mode) end = time.time() elapsed_time = end - start @@ -352,7 +372,9 @@ async def graph_query( document_names: str = Form(None), ): try: - # print(document_names) + payload_json_obj = {'api_name':'graph_query', 'db_url':uri, 'userName':userName, 'database':database, 'document_names':document_names, + 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(payload_json_obj, "INFO") start = time.time() result = await asyncio.to_thread( get_graph_results, @@ -380,6 +402,8 @@ async def graph_query( @app.post("/clear_chat_bot") async def clear_chat_bot(uri=Form(),userName=Form(), password=Form(), database=Form(), session_id=Form(None)): try: + payload_json_obj = {'api_name':'clear_chat_bot', 'db_url':uri, 'userName':userName, 'database':database, 'session_id':session_id, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(payload_json_obj, "INFO") graph = create_graph_database_connection(uri, userName, password, database) result = await asyncio.to_thread(clear_chat_history,graph=graph,session_id=session_id) return create_api_response('Success',data=result) @@ -396,6 +420,8 @@ async def clear_chat_bot(uri=Form(),userName=Form(), password=Form(), database=F async def connect(uri=Form(), userName=Form(), password=Form(), database=Form()): try: start = time.time() + payload_json_obj = {'api_name':'connect', 'db_url':uri, 'userName':userName, 'database':database, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(payload_json_obj, "INFO") graph = create_graph_database_connection(uri, userName, password, database) result = await asyncio.to_thread(connection_check_and_get_vector_dimensions, graph, database) end = time.time() @@ -417,6 +443,9 @@ async def upload_large_file_into_chunks(file:UploadFile = File(...), chunkNumber password=Form(), database=Form()): try: start = time.time() + payload_json_obj = {'api_name':'upload', 'db_url':uri, 'userName':userName, 'database':database, 'chunkNumber':chunkNumber,'totalChunks':totalChunks, + 'original_file_name':originalname,'model':model, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(payload_json_obj, "INFO") graph = create_graph_database_connection(uri, userName, password, database) result = await asyncio.to_thread(upload_file, graph, model, file, chunkNumber, totalChunks, originalname, uri, CHUNK_DIR, MERGED_DIR) end = time.time() @@ -442,6 +471,8 @@ async def upload_large_file_into_chunks(file:UploadFile = File(...), chunkNumber async def get_structured_schema(uri=Form(), userName=Form(), password=Form(), database=Form()): try: start = time.time() + payload_json_obj = {'api_name':'schema', 'db_url':uri, 'userName':userName, 'database':database, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(payload_json_obj, "INFO") graph = create_graph_database_connection(uri, userName, password, database) result = await asyncio.to_thread(get_labels_and_relationtypes, graph) end = time.time() @@ -512,6 +543,9 @@ async def delete_document_and_entities(uri=Form(), deleteEntities=Form()): try: start = time.time() + payload_json_obj = {'api_name':'delete_document_and_entities', 'db_url':uri, 'userName':userName, 'database':database, 'filenames':filenames,'deleteEntities':deleteEntities, + 'source_types':source_types, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(payload_json_obj, "INFO") graph = create_graph_database_connection(uri, userName, password, database) graphDb_data_Access = graphDBdataAccess(graph) result, files_list_size = await asyncio.to_thread(graphDb_data_Access.delete_file_from_graph, filenames, source_types, deleteEntities, MERGED_DIR, uri) @@ -568,6 +602,9 @@ async def get_document_status(file_name, url, userName, password, database): @app.post("/cancelled_job") async def cancelled_job(uri=Form(), userName=Form(), password=Form(), database=Form(), filenames=Form(None), source_types=Form(None)): try: + payload_json_obj = {'api_name':'cancelled_job', 'db_url':uri, 'userName':userName, 'database':database, + 'filenames':filenames,'source_types':source_types,'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(payload_json_obj, "INFO") graph = create_graph_database_connection(uri, userName, password, database) result = manually_cancelled_job(graph,filenames, source_types, MERGED_DIR, uri) @@ -584,6 +621,8 @@ async def cancelled_job(uri=Form(), userName=Form(), password=Form(), database=F @app.post("/populate_graph_schema") async def populate_graph_schema(input_text=Form(None), model=Form(None), is_schema_description_checked=Form(None)): try: + payload_json_obj = {'api_name':'populate_graph_schema', 'model':model, 'is_schema_description_checked':is_schema_description_checked, 'input_text':input_text, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(payload_json_obj, "INFO") result = populate_graph_schema_from_text(input_text, model, is_schema_description_checked) return create_api_response('Success',data=result) except Exception as e: @@ -598,6 +637,8 @@ async def populate_graph_schema(input_text=Form(None), model=Form(None), is_sche @app.post("/get_unconnected_nodes_list") async def get_unconnected_nodes_list(uri=Form(), userName=Form(), password=Form(), database=Form()): try: + payload_json_obj = {'api_name':'get_unconnected_nodes_list', 'db_url':uri, 'userName':userName, 'database':database, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(payload_json_obj, "INFO") start = time.time() graph = create_graph_database_connection(uri, userName, password, database) graphDb_data_Access = graphDBdataAccess(graph) @@ -619,6 +660,9 @@ async def get_unconnected_nodes_list(uri=Form(), userName=Form(), password=Form( @app.post("/delete_unconnected_nodes") async def delete_orphan_nodes(uri=Form(), userName=Form(), password=Form(), database=Form(),unconnected_entities_list=Form()): try: + payload_json_obj = {'api_name':'delete_unconnected_nodes', 'db_url':uri, 'userName':userName, 'database':database, + 'unconnected_entities_list':unconnected_entities_list, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(payload_json_obj, "INFO") start = time.time() graph = create_graph_database_connection(uri, userName, password, database) graphDb_data_Access = graphDBdataAccess(graph) @@ -641,6 +685,8 @@ async def delete_orphan_nodes(uri=Form(), userName=Form(), password=Form(), data async def get_duplicate_nodes(uri=Form(), userName=Form(), password=Form(), database=Form()): try: start = time.time() + payload_json_obj = {'api_name':'get_duplicate_nodes', 'db_url':uri, 'userName':userName, 'database':database, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(payload_json_obj, "INFO") graph = create_graph_database_connection(uri, userName, password, database) graphDb_data_Access = graphDBdataAccess(graph) nodes_list, total_nodes = graphDb_data_Access.get_duplicate_nodes_list() @@ -662,6 +708,9 @@ async def get_duplicate_nodes(uri=Form(), userName=Form(), password=Form(), data async def merge_duplicate_nodes(uri=Form(), userName=Form(), password=Form(), database=Form(),duplicate_nodes_list=Form()): try: start = time.time() + payload_json_obj = {'api_name':'merge_duplicate_nodes', 'db_url':uri, 'userName':userName, 'database':database, + 'duplicate_nodes_list':duplicate_nodes_list, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(payload_json_obj, "INFO") graph = create_graph_database_connection(uri, userName, password, database) graphDb_data_Access = graphDBdataAccess(graph) result = graphDb_data_Access.merge_duplicate_nodes(duplicate_nodes_list) @@ -682,6 +731,9 @@ async def merge_duplicate_nodes(uri=Form(), userName=Form(), password=Form(), da @app.post("/drop_create_vector_index") async def merge_duplicate_nodes(uri=Form(), userName=Form(), password=Form(), database=Form(), isVectorIndexExist=Form()): try: + payload_json_obj = {'api_name':'drop_create_vector_index', 'db_url':uri, 'userName':userName, 'database':database, + 'isVectorIndexExist':isVectorIndexExist, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(payload_json_obj, "INFO") graph = create_graph_database_connection(uri, userName, password, database) graphDb_data_Access = graphDBdataAccess(graph) result = graphDb_data_Access.drop_create_vector_index(isVectorIndexExist) @@ -698,6 +750,9 @@ async def merge_duplicate_nodes(uri=Form(), userName=Form(), password=Form(), da @app.post("/retry_processing") async def retry_processing(uri=Form(), userName=Form(), password=Form(), database=Form(), file_name=Form(), retry_condition=Form()): try: + payload_json_obj = {'api_name':'retry_processing', 'db_url':uri, 'userName':userName, 'database':database, 'file_name':file_name,'retry_condition':retry_condition, + 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(payload_json_obj, "INFO") graph = create_graph_database_connection(uri, userName, password, database) await asyncio.to_thread(set_status_retry, graph,file_name,retry_condition) #set_status_retry(graph,file_name,retry_condition) @@ -714,14 +769,16 @@ async def retry_processing(uri=Form(), userName=Form(), password=Form(), databas @app.post('/metric') async def calculate_metric(question=Form(), context=Form(), answer=Form(), model=Form()): try: - result = await asyncio.to_thread(get_ragas_metrics, question, context, answer, model) - if result is None or "error" in result: - return create_api_response( - 'Failed', - message='Failed to calculate evaluation metrics.', - error=result.get("error", "Ragas evaluation returned null") - ) - return create_api_response('Success', data=result) + payload_json_obj = {'api_name':'metric', 'context':context, 'answer':answer, 'model':model, 'logging_time': formatted_time(datetime.now(timezone.utc))} + logger.log_struct(payload_json_obj, "INFO") + result = await asyncio.to_thread(get_ragas_metrics, question, context, answer, model) + if result is None or "error" in result: + return create_api_response( + 'Failed', + message='Failed to calculate evaluation metrics.', + error=result.get("error", "Ragas evaluation returned null") + ) + return create_api_response('Success', data=result) except Exception as e: job_status = "Failed" message = "Error while calculating evaluation metrics" From a8f821afed802405f7997300b4e6622c968429a2 Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Fri, 18 Oct 2024 17:54:11 +0530 Subject: [PATCH 184/292] Adding Links to get neighboring nodes (#796) * addition of link * added neighbours query * implemented with driver * updated the query * communitiesInfo name change * communities.tsx removed * api integration * modified response * entities change * chunk and communities * chunk space removal * added element id to chunks * loading on click * format changes * added file name for Dcoumrnt node * chat token cut off model name update * icon change * duplicate sources removal * Entity change --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> --- backend/score.py | 20 ++ backend/src/chunkid_entities.py | 13 +- backend/src/neighbours.py | 63 ++++++ backend/src/shared/constants.py | 16 +- .../src/components/ChatBot/ChatInfoModal.tsx | 13 +- .../components/ChatBot/ChatModesSwitch.tsx | 2 + frontend/src/components/ChatBot/ChunkInfo.tsx | 135 ++++++++++-- .../components/ChatBot/CommonChatActions.tsx | 3 + .../src/components/ChatBot/Communities.tsx | 41 ---- .../components/ChatBot/CommunitiesInfo.tsx | 45 +++- .../src/components/ChatBot/EntitiesInfo.tsx | 102 +++++++-- .../src/components/ChatBot/SourcesInfo.tsx | 23 +- frontend/src/components/ChatBot/chatInfo.ts | 40 ++++ .../src/components/Graph/GraphViewButton.tsx | 6 +- .../src/components/Graph/GraphViewModal.tsx | 12 +- .../Deduplication/index.tsx | 202 ++++++++++------- .../DeleteTabForOrphanNodes/index.tsx | 205 ++++++++++-------- .../EntityExtractionSetting.tsx | 39 +++- frontend/src/services/GraphQuery.ts | 24 +- frontend/src/types.ts | 32 +++ frontend/src/utils/Constants.ts | 2 + 21 files changed, 762 insertions(+), 276 deletions(-) create mode 100644 backend/src/neighbours.py delete mode 100644 frontend/src/components/ChatBot/Communities.tsx create mode 100644 frontend/src/components/ChatBot/chatInfo.ts diff --git a/backend/score.py b/backend/score.py index 1efd46f86..7940815b2 100644 --- a/backend/score.py +++ b/backend/score.py @@ -17,6 +17,7 @@ from src.post_processing import create_vector_fulltext_indexes, create_entity_embedding from sse_starlette.sse import EventSourceResponse from src.communities import create_communities +from src.neighbours import get_neighbour_nodes import json from typing import List, Mapping from starlette.middleware.sessions import SessionMiddleware @@ -363,6 +364,25 @@ async def chunk_entities(uri=Form(),userName=Form(), password=Form(), database=F finally: gc.collect() +@app.post("/get_neighbours") +async def get_neighbours(uri=Form(),userName=Form(), password=Form(), database=Form(), elementId=Form(None)): + try: + start = time.time() + result = await asyncio.to_thread(get_neighbour_nodes,uri=uri, username=userName, password=password,database=database, element_id=elementId) + end = time.time() + elapsed_time = end - start + json_obj = {'api_name':'get_neighbours','db_url':uri, 'logging_time': formatted_time(datetime.now(timezone.utc)), 'elapsed_api_time':f'{elapsed_time:.2f}'} + logger.log_struct(json_obj, "INFO") + return create_api_response('Success',data=result,message=f"Total elapsed API time {elapsed_time:.2f}") + except Exception as e: + job_status = "Failed" + message="Unable to extract neighbour nodes for given element ID" + error_message = str(e) + logging.exception(f'Exception in get neighbours :{error_message}') + return create_api_response(job_status, message=message, error=error_message) + finally: + gc.collect() + @app.post("/graph_query") async def graph_query( uri: str = Form(), diff --git a/backend/src/chunkid_entities.py b/backend/src/chunkid_entities.py index 8bb9c2198..31ae07496 100644 --- a/backend/src/chunkid_entities.py +++ b/backend/src/chunkid_entities.py @@ -1,6 +1,7 @@ import logging from src.graph_query import * from src.shared.constants import * +import re def process_records(records): """ @@ -191,7 +192,11 @@ def get_entities_from_chunkids(uri, username, password, database ,nodedetails,en if "entitydetails" in nodedetails and nodedetails["entitydetails"]: entity_ids = [item["id"] for item in nodedetails["entitydetails"]] logging.info(f"chunkid_entities module: Starting for entity ids: {entity_ids}") - return process_entityids(driver, entity_ids) + result = process_entityids(driver, entity_ids) + if "chunk_data" in result.keys(): + for chunk in result["chunk_data"]: + chunk["text"] = re.sub(r'\s+', ' ', chunk["text"]) + return result else: logging.info("chunkid_entities module: No entity ids are passed") return default_response @@ -201,7 +206,11 @@ def get_entities_from_chunkids(uri, username, password, database ,nodedetails,en if "chunkdetails" in nodedetails and nodedetails["chunkdetails"]: chunk_ids = [item["id"] for item in nodedetails["chunkdetails"]] logging.info(f"chunkid_entities module: Starting for chunk ids: {chunk_ids}") - return process_chunkids(driver, chunk_ids, entities) + result = process_chunkids(driver, chunk_ids, entities) + if "chunk_data" in result.keys(): + for chunk in result["chunk_data"]: + chunk["text"] = re.sub(r'\s+', ' ', chunk["text"]) + return result else: logging.info("chunkid_entities module: No chunk ids are passed") return default_response diff --git a/backend/src/neighbours.py b/backend/src/neighbours.py new file mode 100644 index 000000000..08022ecc6 --- /dev/null +++ b/backend/src/neighbours.py @@ -0,0 +1,63 @@ +import logging +from src.graph_query import * + +NEIGHBOURS_FROM_ELEMENT_ID_QUERY = """ +MATCH (n) +WHERE elementId(n) = $element_id + +MATCH (n)<-[rels]->(m) +WITH n, + ([n] + COLLECT(DISTINCT m)) AS allNodes, + COLLECT(DISTINCT rels) AS allRels + +RETURN + [node IN allNodes | + node { + .*, + embedding: null, + text: null, + summary: null, + labels: [coalesce(apoc.coll.removeAll(labels(node), ['__Entity__'])[0], "*")], + element_id: elementId(node), + properties: { + id: CASE WHEN node.id IS NOT NULL THEN node.id ELSE node.fileName END + } + } + ] AS nodes, + + [r IN allRels | + { + start_node_element_id: elementId(startNode(r)), + end_node_element_id: elementId(endNode(r)), + type: type(r), + element_id: elementId(r) + } + ] AS relationships +""" + + +def get_neighbour_nodes(uri, username, password, database, element_id, query=NEIGHBOURS_FROM_ELEMENT_ID_QUERY): + driver = None + + try: + logging.info(f"Querying neighbours for element_id: {element_id}") + driver = get_graphDB_driver(uri, username, password, database) + driver.verify_connectivity() + logging.info("Database connectivity verified.") + + records, summary, keys = driver.execute_query(query,element_id=element_id) + nodes = records[0].get("nodes", []) + relationships = records[0].get("relationships", []) + result = {"nodes": nodes, "relationships": relationships} + + logging.info(f"Successfully retrieved neighbours for element_id: {element_id}") + return result + + except Exception as e: + logging.error(f"Error retrieving neighbours for element_id: {element_id}: {e}") + return {"nodes": [], "relationships": []} + + finally: + if driver is not None: + driver.close() + logging.info("Database driver closed.") \ No newline at end of file diff --git a/backend/src/shared/constants.py b/backend/src/shared/constants.py index 33b27b20a..cde354f16 100644 --- a/backend/src/shared/constants.py +++ b/backend/src/shared/constants.py @@ -121,7 +121,7 @@ RETURN d AS doc, [chunk IN chunks | - chunk {.*, embedding: null} + chunk {.*, embedding: null, element_id: elementId(chunk)} ] AS chunks, [ node IN nodes | @@ -168,10 +168,10 @@ CHAT_EMBEDDING_FILTER_SCORE_THRESHOLD = 0.10 CHAT_TOKEN_CUT_OFF = { - ("openai-gpt-3.5",'azure_ai_gpt_35',"gemini-1.0-pro","gemini-1.5-pro", "gemini-1.5-flash","groq-llama3",'groq_llama3_70b','anthropic_claude_3_5_sonnet','fireworks_llama_v3_70b','bedrock_claude_3_5_sonnet', ) : 4, - ("openai-gpt-4","diffbot" ,'azure_ai_gpt_4o',"openai-gpt-4o", "openai-gpt-4o-mini") : 28, + ('openai_gpt_3.5','azure_ai_gpt_35',"gemini_1.0_pro","gemini_1.5_pro", "gemini_1.5_flash","groq-llama3",'groq_llama3_70b','anthropic_claude_3_5_sonnet','fireworks_llama_v3_70b','bedrock_claude_3_5_sonnet', ) : 4, + ("openai-gpt-4","diffbot" ,'azure_ai_gpt_4o',"openai_gpt_4o", "openai_gpt_4o_mini") : 28, ("ollama_llama3") : 2 -} +} ### CHAT TEMPLATES CHAT_SYSTEM_TEMPLATE = """ @@ -473,14 +473,16 @@ .*, embedding: null, fileName: d.fileName, - fileSource: d.fileSource + fileSource: d.fileSource, + element_id: elementId(c) } ] AS chunks, [ community IN communities WHERE community IS NOT NULL | community { .*, - embedding: null + embedding: null, + element_id:elementId(community) } ] AS communities, [ @@ -551,7 +553,7 @@ WHERE elementId(community) IN $communityids WITH collect(distinct community) AS communities RETURN [community IN communities | - community {.*, embedding: null, elementid: elementId(community)}] AS communities + community {.*, embedding: null, element_id: elementId(community)}] AS communities """ ## CHAT MODES diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index 7fb819a32..266bf98ac 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -23,7 +23,7 @@ import { tokens } from '@neo4j-ndl/base'; import ChunkInfo from './ChunkInfo'; import EntitiesInfo from './EntitiesInfo'; import SourcesInfo from './SourcesInfo'; -import CommunitiesInfo from './Communities'; +import CommunitiesInfo from './CommunitiesInfo'; import { chatModeLables, supportedLLmsForRagas } from '../../utils/Constants'; import { Relationship } from '@neo4j-nvl/base'; import { getChatMetrics } from '../../services/GetRagasMetric'; @@ -74,6 +74,8 @@ const ChatInfoModal: React.FC = ({ const [copiedText, setcopiedText] = useState(false); const [showMetricsTable, setShowMetricsTable] = useState(Boolean(metricDetails)); + console.log('node', nodeDetails); + const actions: CypherCodeBlockProps['actions'] = useMemo( () => [ { @@ -348,9 +350,14 @@ const ChatInfoModal: React.FC = ({ <> )} - {activeTab == 4 && nodes?.length && relationships?.length ? ( + {activeTab == 4 && nodes?.length && relationships?.length && mode !== chatModeLables.graph ? ( - + ) : ( <> diff --git a/frontend/src/components/ChatBot/ChatModesSwitch.tsx b/frontend/src/components/ChatBot/ChatModesSwitch.tsx index 5bde10d26..a958b1a06 100644 --- a/frontend/src/components/ChatBot/ChatModesSwitch.tsx +++ b/frontend/src/components/ChatBot/ChatModesSwitch.tsx @@ -24,6 +24,7 @@ export default function ChatModesSwitch({ size='small' clean onClick={() => switchToOtherMode(currentModeIndex - 1)} + aria-label='left' > @@ -39,6 +40,7 @@ export default function ChatModesSwitch({ size='small' clean onClick={() => switchToOtherMode(currentModeIndex + 1)} + aria-label='right' > diff --git a/frontend/src/components/ChatBot/ChunkInfo.tsx b/frontend/src/components/ChatBot/ChunkInfo.tsx index 05fa229a1..7f31cd4d5 100644 --- a/frontend/src/components/ChatBot/ChunkInfo.tsx +++ b/frontend/src/components/ChatBot/ChunkInfo.tsx @@ -1,7 +1,7 @@ -import { FC, useContext } from 'react'; -import { ChunkProps } from '../../types'; +import { FC, useContext, useState } from 'react'; +import { ChunkProps, UserCredentials } from '../../types'; import { Box, LoadingSpinner, TextLink, Typography } from '@neo4j-ndl/react'; -import { DocumentTextIconOutline, GlobeAltIconOutline } from '@neo4j-ndl/react/icons'; +import { DocumentTextIconOutline, GlobeAltIconOutline, MagnifyingGlassCircleIconSolid } from '@neo4j-ndl/react/icons'; import wikipedialogo from '../../assets/images/wikipedia.svg'; import youtubelogo from '../../assets/images/youtube.svg'; import gcslogo from '../../assets/images/gcs.webp'; @@ -10,9 +10,32 @@ import ReactMarkdown from 'react-markdown'; import { generateYouTubeLink, getLogo, isAllowedHost } from '../../utils/Utils'; import { ThemeWrapperContext } from '../../context/ThemeWrapper'; import { chatModeLables } from '../../utils/Constants'; +import { useCredentials } from '../../context/UserCredentials'; +import GraphViewModal from '../Graph/GraphViewModal'; +import { handleGraphNodeClick } from './chatInfo'; +import { IconButtonWithToolTip } from '../UI/IconButtonToolTip'; const ChunkInfo: FC = ({ loading, chunks, mode }) => { const themeUtils = useContext(ThemeWrapperContext); + const { userCredentials } = useCredentials(); + const [neoNodes, setNeoNodes] = useState([]); + const [neoRels, setNeoRels] = useState([]); + const [openGraphView, setOpenGraphView] = useState(false); + const [viewPoint, setViewPoint] = useState(''); + const [loadingGraphView, setLoadingGraphView] = useState(false); + + const handleChunkClick = async (elementId: string, viewMode: string) => { + handleGraphNodeClick( + userCredentials as UserCredentials, + elementId, + viewMode, + setNeoNodes, + setNeoRels, + setOpenGraphView, + setViewPoint, + setLoadingGraphView + ); + }; return ( <> @@ -28,23 +51,49 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { {chunk?.page_number ? ( <>
    - - - {chunk?.fileName} - + <> + handleChunkClick(chunk.element_id, 'Chunk')} + > + + + + + {chunk?.fileName} + +
    {mode !== chatModeLables.global_vector && mode !== chatModeLables.entity_vector && - mode !== chatModeLables.graph && ( + mode !== chatModeLables.graph && + chunk.score && ( Similarity Score: {chunk?.score} )} +
    + Page: {chunk?.page_number} +
    ) : chunk?.url && chunk?.start_time ? ( <>
    + handleChunkClick(chunk.element_id, 'Chunk')} + > + + = ({ loading, chunks, mode }) => { ) : chunk?.url && new URL(chunk.url).host === 'wikipedia.org' ? ( <>
    + handleChunkClick(chunk.element_id, 'Chunk')} + > + + {chunk?.fileName}
    @@ -76,6 +135,16 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { ) : chunk?.url && new URL(chunk.url).host === 'storage.googleapis.com' ? ( <>
    + handleChunkClick(chunk.element_id, 'Chunk')} + > + + {chunk?.fileName}
    @@ -88,6 +157,16 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { ) : chunk?.url && chunk?.url.startsWith('s3://') ? ( <>
    + handleChunkClick(chunk.element_id, 'Chunk')} + > + + {chunk?.fileName}
    @@ -102,6 +181,16 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { !isAllowedHost(chunk?.url, ['storage.googleapis.com', 'wikipedia.org', 'youtube.com']) ? ( <>
    + handleChunkClick(chunk.element_id, 'Chunk')} + > + + {chunk?.url} @@ -116,6 +205,16 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { ) : ( <>
    + handleChunkClick(chunk.element_id, 'Chunk')} + > + + {chunk.fileSource === 'local file' ? ( ) : ( @@ -135,7 +234,9 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => {
    )} - {chunk?.text} +
    + {chunk?.text} +
    ))} @@ -143,8 +244,16 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { ) : ( No Chunks Found )} + {openGraphView && ( + + )} ); }; - export default ChunkInfo; diff --git a/frontend/src/components/ChatBot/CommonChatActions.tsx b/frontend/src/components/ChatBot/CommonChatActions.tsx index 80d904f6a..d1a5c6243 100644 --- a/frontend/src/components/ChatBot/CommonChatActions.tsx +++ b/frontend/src/components/ChatBot/CommonChatActions.tsx @@ -30,6 +30,7 @@ export default function CommonActions({ label='Retrieval Information' disabled={chat.isTyping || chat.isLoading} onClick={() => detailsHandler(chat, activeChat)} + aria-label='Retrieval Information' > {buttonCaptions.details} @@ -40,6 +41,7 @@ export default function CommonActions({ text={chat.copying ? tooltips.copied : tooltips.copy} onClick={() => copyHandler(chat.modes[chat.currentMode]?.message, chat.id)} disabled={chat.isTyping || chat.isLoading} + aria-label='copy text' > @@ -50,6 +52,7 @@ export default function CommonActions({ text={chat.speaking ? tooltips.stopSpeaking : tooltips.textTospeech} disabled={listMessages.some((msg) => msg.speaking && msg.id !== chat.id)} label={chat.speaking ? 'stop speaking' : 'text to speech'} + aria-label='speech' > {chat.speaking ? : } diff --git a/frontend/src/components/ChatBot/Communities.tsx b/frontend/src/components/ChatBot/Communities.tsx deleted file mode 100644 index 11869d3d4..000000000 --- a/frontend/src/components/ChatBot/Communities.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { Box, LoadingSpinner, Flex, Typography } from '@neo4j-ndl/react'; -import { FC } from 'react'; -import ReactMarkdown from 'react-markdown'; -import { CommunitiesProps } from '../../types'; - -const CommunitiesInfo: FC = ({ loading, communities }) => { - console.log('communities', communities); - return ( - <> - {loading ? ( - - - - ) : communities?.length > 0 ? ( -
    -
      - {communities.map((community, index) => ( -
    • -
      - - ID : - {community.id} - - - Score : - {community.score} - - {community.summary} -
      -
    • - ))} -
    -
    - ) : ( - No Communities Found - )} - - ); -}; - -export default CommunitiesInfo; diff --git a/frontend/src/components/ChatBot/CommunitiesInfo.tsx b/frontend/src/components/ChatBot/CommunitiesInfo.tsx index 088e4e370..f562a4ed4 100644 --- a/frontend/src/components/ChatBot/CommunitiesInfo.tsx +++ b/frontend/src/components/ChatBot/CommunitiesInfo.tsx @@ -1,10 +1,33 @@ -import { Box, LoadingSpinner, Flex, Typography } from '@neo4j-ndl/react'; -import { FC } from 'react'; +import { Box, LoadingSpinner, Flex, Typography, TextLink } from '@neo4j-ndl/react'; +import { FC, useState } from 'react'; import ReactMarkdown from 'react-markdown'; -import { CommunitiesProps } from '../../types'; +import { CommunitiesProps, UserCredentials } from '../../types'; import { chatModeLables } from '../../utils/Constants'; +import { useCredentials } from '../../context/UserCredentials'; +import GraphViewModal from '../Graph/GraphViewModal'; +import { handleGraphNodeClick } from './chatInfo'; const CommunitiesInfo: FC = ({ loading, communities, mode }) => { + const { userCredentials } = useCredentials(); + const [neoNodes, setNeoNodes] = useState([]); + const [neoRels, setNeoRels] = useState([]); + const [openGraphView, setOpenGraphView] = useState(false); + const [viewPoint, setViewPoint] = useState(''); + const [loadingGraphView, setLoadingGraphView] = useState(false); + + const handleCommunityClick = (elementId: string, viewMode: string) => { + handleGraphNodeClick( + userCredentials as UserCredentials, + elementId, + viewMode, + setNeoNodes, + setNeoRels, + setOpenGraphView, + setViewPoint, + setLoadingGraphView + ); + }; + return ( <> {loading ? ( @@ -18,8 +41,11 @@ const CommunitiesInfo: FC = ({ loading, communities, mode }) =
  • - ID : - {community.id} + handleCommunityClick(community.element_id, 'chatInfoView')} + >{`ID : ${community.id}`} {mode === chatModeLables.global_vector && community.score && ( @@ -36,6 +62,15 @@ const CommunitiesInfo: FC = ({ loading, communities, mode }) = ) : ( No Communities Found )} + {openGraphView && ( + + )} ); }; diff --git a/frontend/src/components/ChatBot/EntitiesInfo.tsx b/frontend/src/components/ChatBot/EntitiesInfo.tsx index 6c6e0784e..2b1ff3cca 100644 --- a/frontend/src/components/ChatBot/EntitiesInfo.tsx +++ b/frontend/src/components/ChatBot/EntitiesInfo.tsx @@ -1,11 +1,21 @@ -import { Box, GraphLabel, LoadingSpinner, Typography } from '@neo4j-ndl/react'; -import { FC, useMemo } from 'react'; -import { EntitiesProps, GroupedEntity } from '../../types'; +import { Box, GraphLabel, LoadingSpinner, TextLink, Typography } from '@neo4j-ndl/react'; +import { FC, useMemo, useState } from 'react'; +import { EntitiesProps, GroupedEntity, UserCredentials } from '../../types'; import { calcWordColor } from '@neo4j-devtools/word-color'; import { graphLabels } from '../../utils/Constants'; import { parseEntity } from '../../utils/Utils'; +import { useCredentials } from '../../context/UserCredentials'; +import GraphViewModal from '../Graph/GraphViewModal'; +import { handleGraphNodeClick } from './chatInfo'; const EntitiesInfo: FC = ({ loading, mode, graphonly_entities, infoEntities }) => { + const { userCredentials } = useCredentials(); + const [neoNodes, setNeoNodes] = useState([]); + const [neoRels, setNeoRels] = useState([]); + const [openGraphView, setOpenGraphView] = useState(false); + const [viewPoint, setViewPoint] = useState(''); + const [loadingGraphView, setLoadingGraphView] = useState(false); + const groupedEntities = useMemo<{ [key: string]: GroupedEntity }>(() => { const items = infoEntities.reduce((acc, entity) => { const { label, text } = parseEntity(entity); @@ -18,7 +28,6 @@ const EntitiesInfo: FC = ({ loading, mode, graphonly_entities, in }, {} as Record; color: string }>); return items; }, [infoEntities]); - const labelCounts = useMemo(() => { const counts: { [label: string]: number } = {}; for (let index = 0; index < infoEntities?.length; index++) { @@ -33,26 +42,55 @@ const EntitiesInfo: FC = ({ loading, mode, graphonly_entities, in const sortedLabels = useMemo(() => { return Object.keys(labelCounts).sort((a, b) => labelCounts[b] - labelCounts[a]); }, [labelCounts]); + + const handleEntityClick = async (elementId: string, viewMode: string) => { + handleGraphNodeClick( + userCredentials as UserCredentials, + elementId, + viewMode, + setNeoNodes, + setNeoRels, + setOpenGraphView, + setViewPoint, + setLoadingGraphView + ); + }; + return ( <> {loading ? ( - ) : Object.keys(groupedEntities)?.length > 0 || Object.keys(graphonly_entities)?.length > 0 ? ( + ) : (mode !== 'graph' && Object.keys(groupedEntities)?.length > 0) || + (mode == 'graph' && Object.keys(graphonly_entities)?.length > 0) ? (
      {mode == 'graph' ? graphonly_entities.map((label, index) => (
    • -
      - { - // @ts-ignore - label[Object.keys(label)[0]].id ?? Object.keys(label)[0] - } -
      +
        + {Object.keys(label).map((key) => ( +
      • + + {key} + + + { + // @ts-ignore + label[key].id ?? label[key] + } + +
      • + ))} +
    • )) : sortedLabels.map((label, index) => { @@ -62,20 +100,32 @@ const EntitiesInfo: FC = ({ loading, mode, graphonly_entities, in key={index} className='flex items-center mb-2 text-ellipsis whitespace-nowrap max-w-[100%)] overflow-hidden' > - e.preventDefault()} - > + {label === '__Community__' ? graphLabels.community : label} ({labelCounts[label]}) - {Array.from(entity.texts).slice(0, 3).join(', ')} + {Array.from(entity.texts) + .slice(0, 3) + .map((text, idx) => { + const matchingEntity = infoEntities.find( + (e) => e.labels.includes(label) && parseEntity(e).text === text + ); + const textId = matchingEntity?.element_id; + return ( + + handleEntityClick(textId!, 'chatInfoView')} + className={loadingGraphView ? 'cursor-wait' : 'cursor-pointer'} + > + {text} + + {Array.from(entity.texts).length > 1 ? ',' : ''} + + ); + })} ); @@ -84,8 +134,16 @@ const EntitiesInfo: FC = ({ loading, mode, graphonly_entities, in ) : ( No Entities Found )} + {openGraphView && ( + + )} ); }; - export default EntitiesInfo; diff --git a/frontend/src/components/ChatBot/SourcesInfo.tsx b/frontend/src/components/ChatBot/SourcesInfo.tsx index 91fee511f..79d710fa2 100644 --- a/frontend/src/components/ChatBot/SourcesInfo.tsx +++ b/frontend/src/components/ChatBot/SourcesInfo.tsx @@ -1,5 +1,5 @@ import { FC, useContext } from 'react'; -import { SourcesProps } from '../../types'; +import { Chunk, SourcesProps } from '../../types'; import { Box, LoadingSpinner, TextLink, Typography } from '@neo4j-ndl/react'; import { DocumentTextIconOutline, GlobeAltIconOutline } from '@neo4j-ndl/react/icons'; import { getLogo, isAllowedHost, youtubeLinkValidation } from '../../utils/Utils'; @@ -10,17 +10,31 @@ import youtubelogo from '../../assets/images/youtube.svg'; import gcslogo from '../../assets/images/gcs.webp'; import s3logo from '../../assets/images/s3logo.png'; +const filterUniqueChunks = (chunks: Chunk[]) => { + const chunkSource = new Set(); + return chunks.filter(chunk => { + const sourceCheck = `${chunk.fileName}-${chunk.fileSource}`; + if (chunkSource.has(sourceCheck)) { + return false; + } else { + chunkSource.add(sourceCheck); + return true; + } + }); +}; + const SourcesInfo: FC = ({ loading, mode, chunks, sources }) => { const themeUtils = useContext(ThemeWrapperContext); + const uniqueChunks = chunks ? filterUniqueChunks(chunks) : []; return ( <> {loading ? ( - ) : mode === 'entity search+vector' && chunks?.length ? ( + ) : mode === 'entity search+vector' && uniqueChunks.length ? (
        - {chunks + {uniqueChunks .map((c) => ({ fileName: c.fileName, fileSource: c.fileSource })) .map((s, index) => { return ( @@ -133,5 +147,4 @@ const SourcesInfo: FC = ({ loading, mode, chunks, sources }) => { ); }; - -export default SourcesInfo; +export default SourcesInfo; \ No newline at end of file diff --git a/frontend/src/components/ChatBot/chatInfo.ts b/frontend/src/components/ChatBot/chatInfo.ts new file mode 100644 index 000000000..821cf69f8 --- /dev/null +++ b/frontend/src/components/ChatBot/chatInfo.ts @@ -0,0 +1,40 @@ +import { getNeighbors } from '../../services/GraphQuery'; +import { NeoNode, NeoRelationship, UserCredentials } from '../../types'; + +export const handleGraphNodeClick = async ( + userCredentials: UserCredentials, + elementId: string, + viewMode: string, + setNeoNodes: React.Dispatch>, + setNeoRels: React.Dispatch>, + setOpenGraphView: React.Dispatch>, + setViewPoint: React.Dispatch>, + setLoadingGraphView?: React.Dispatch> +) => { + if (setLoadingGraphView) { + setLoadingGraphView(true); + } + try { + const result = await getNeighbors(userCredentials, elementId); + if (result && result.data.data.nodes.length > 0) { + let { nodes } = result.data.data; + if (viewMode === 'Chunk') { + nodes = nodes.filter((node: NeoNode) => node.labels.length === 1 && node.properties.id !== null); + } + const nodeIds = new Set(nodes.map((node: NeoNode) => node.element_id)); + const relationships = result.data.data.relationships.filter( + (rel: NeoRelationship) => nodeIds.has(rel.end_node_element_id) && nodeIds.has(rel.start_node_element_id) + ); + setNeoNodes(nodes); + setNeoRels(relationships); + setOpenGraphView(true); + setViewPoint('chatInfoView'); + } + } catch (error: any) { + console.error('Error fetching neighbors:', error); + } finally { + if (setLoadingGraphView) { + setLoadingGraphView(false); + } + } +}; diff --git a/frontend/src/components/Graph/GraphViewButton.tsx b/frontend/src/components/Graph/GraphViewButton.tsx index 50eb13972..8f051ce0b 100644 --- a/frontend/src/components/Graph/GraphViewButton.tsx +++ b/frontend/src/components/Graph/GraphViewButton.tsx @@ -3,7 +3,7 @@ import { Button } from '@neo4j-ndl/react'; import GraphViewModal from './GraphViewModal'; import { GraphViewButtonProps } from '../../types'; -const GraphViewButton: React.FC = ({ nodeValues, relationshipValues }) => { +const GraphViewButton: React.FC = ({ nodeValues, relationshipValues, fill, label }) => { const [openGraphView, setOpenGraphView] = useState(false); const [viewPoint, setViewPoint] = useState(''); @@ -13,7 +13,9 @@ const GraphViewButton: React.FC = ({ nodeValues, relations }; return ( <> - + = ({ if (open) { setLoading(true); setGraphType([]); - if (viewPoint !== 'chatInfoView') { + if (viewPoint !== graphLabels.chatInfoView) { graphApi(); } else { const { finalNodes, finalRels, schemeVal } = processGraphData(nodeValues ?? [], relationshipValues ?? []); @@ -176,7 +176,9 @@ const GraphViewModal: React.FunctionComponent = ({ }, [open]); useEffect(() => { - handleSearch(debouncedQuery); + if (debouncedQuery) { + handleSearch(debouncedQuery); + } }, [debouncedQuery]); const initGraph = ( @@ -244,7 +246,7 @@ const GraphViewModal: React.FunctionComponent = ({ setNodes(updatedNodes); setRelationships(updatedRelationships); }, - [nodes] + [nodes, relationships] ); // Unmounting the component @@ -377,7 +379,7 @@ const GraphViewModal: React.FunctionComponent = ({
        - ) : graphType.length === 0 ? ( + ) : graphType.length === 0 && checkBoxView ? (
        diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx index f5a021e30..05facb141 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx @@ -12,13 +12,24 @@ import { Row, getSortedRowModel, } from '@tanstack/react-table'; -import { Checkbox, DataGrid, DataGridComponents, Flex, Tag, Typography, useMediaQuery } from '@neo4j-ndl/react'; +import { + Checkbox, + DataGrid, + DataGridComponents, + Flex, + Tag, + TextLink, + Typography, + useMediaQuery, +} from '@neo4j-ndl/react'; import Legend from '../../../UI/Legend'; import { DocumentIconOutline } from '@neo4j-ndl/react/icons'; import { calcWordColor } from '@neo4j-devtools/word-color'; import ButtonWithToolTip from '../../../UI/ButtonWithToolTip'; import mergeDuplicateNodes from '../../../../services/MergeDuplicateEntities'; import { tokens } from '@neo4j-ndl/base'; +import GraphViewModal from '../../../Graph/GraphViewModal'; +import { handleGraphNodeClick } from '../../../ChatBot/chatInfo'; export default function DeduplicationTab() { const { breakpoints } = tokens; @@ -30,6 +41,11 @@ export default function DeduplicationTab() { const [isLoading, setLoading] = useState(false); const [mergeAPIloading, setmergeAPIloading] = useState(false); const tableRef = useRef(null); + const [neoNodes, setNeoNodes] = useState([]); + const [neoRels, setNeoRels] = useState([]); + const [openGraphView, setOpenGraphView] = useState(false); + const [viewPoint, setViewPoint] = useState(''); + const fetchDuplicateNodes = useCallback(async () => { try { setLoading(true); @@ -89,6 +105,19 @@ export default function DeduplicationTab() { ); }); }; + + const handleDuplicateNodeClick = async (elementId: string, viewMode: string) => { + handleGraphNodeClick( + userCredentials as UserCredentials, + elementId, + viewMode, + setNeoNodes, + setNeoRels, + setOpenGraphView, + setViewPoint + ); + }; + const columns = useMemo( () => [ { @@ -121,7 +150,13 @@ export default function DeduplicationTab() { cell: (info) => { return (
        - {info.getValue()} + handleDuplicateNodeClick(info.row.id, 'chatInfoView')} + title={info.getValue()} + > + {info.getValue()} +
        ); }, @@ -225,83 +260,94 @@ export default function DeduplicationTab() { ? `Merge Duplicate Nodes (${table.getSelectedRowModel().rows.length})` : 'Select Node(s) to Merge'; return ( -
        - - - - Refine Your Knowledge Graph: Merge Duplicate Entities: - - - Identify and merge similar entries like "Apple" and "Apple Inc." to eliminate redundancy and improve the - accuracy and clarity of your knowledge graph. - + <> +
        + + + + Refine Your Knowledge Graph: Merge Duplicate Entities: + + + Identify and merge similar entries like "Apple" and "Apple Inc." to eliminate redundancy and improve the + accuracy and clarity of your knowledge graph. + + + {duplicateNodes.length > 0 && ( + + Total Duplicate Nodes: {duplicateNodes.length} + + )} - {duplicateNodes.length > 0 && ( - - Total Duplicate Nodes: {duplicateNodes.length} - - )} - - , - PaginationNumericButton: ({ isSelected, innerProps, ...restProps }) => { - return ( - - ); - }, - }} - /> - - { - await clickHandler(); - await fetchDuplicateNodes(); + - {selectedFilesCheck} - - -
        + rootProps={{ + className: 'max-h-[355px] !overflow-y-auto', + }} + isLoading={isLoading} + components={{ + Body: (props) => , + PaginationNumericButton: ({ isSelected, innerProps, ...restProps }) => { + return ( + + ); + }, + }} + /> + + { + await clickHandler(); + await fetchDuplicateNodes(); + }} + size='large' + loading={mergeAPIloading} + text={ + isLoading + ? 'Fetching Duplicate Nodes' + : !isLoading && !duplicateNodes.length + ? 'No Nodes Found' + : !table.getSelectedRowModel().rows.length + ? 'No Nodes Selected' + : mergeAPIloading + ? 'Merging' + : `Merge Selected Nodes (${table.getSelectedRowModel().rows.length})` + } + label='Merge Duplicate Node Button' + disabled={!table.getSelectedRowModel().rows.length} + placement='top' + > + {selectedFilesCheck} + + +
        + {openGraphView && ( + + )} + ); } diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx index 24de576c5..bcc2597f1 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx @@ -1,4 +1,4 @@ -import { Checkbox, DataGrid, DataGridComponents, Flex, Typography, useMediaQuery } from '@neo4j-ndl/react'; +import { Checkbox, DataGrid, DataGridComponents, Flex, TextLink, Typography, useMediaQuery } from '@neo4j-ndl/react'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { UserCredentials, orphanNodeProps } from '../../../../types'; import { getOrphanNodes } from '../../../../services/GetOrphanNodes'; @@ -19,6 +19,8 @@ import { } from '@tanstack/react-table'; import DeletePopUp from '../../DeletePopUp/DeletePopUp'; import { tokens } from '@neo4j-ndl/base'; +import GraphViewModal from '../../../Graph/GraphViewModal'; +import { handleGraphNodeClick } from '../../../ChatBot/chatInfo'; export default function DeletePopUpForOrphanNodes({ deleteHandler, loading, @@ -35,6 +37,10 @@ export default function DeletePopUpForOrphanNodes({ const [rowSelection, setRowSelection] = useState>({}); const tableRef = useRef(null); const [showDeletePopUp, setshowDeletePopUp] = useState(false); + const [neoNodes, setNeoNodes] = useState([]); + const [neoRels, setNeoRels] = useState([]); + const [openGraphView, setOpenGraphView] = useState(false); + const [viewPoint, setViewPoint] = useState(''); const fetchOrphanNodes = useCallback(async () => { try { @@ -66,6 +72,18 @@ export default function DeletePopUpForOrphanNodes({ }, [userCredentials]); const columnHelper = createColumnHelper(); + const handleOrphanNodeClick = (elementId: string, viewMode: string) => { + handleGraphNodeClick( + userCredentials as UserCredentials, + elementId, + viewMode, + setNeoNodes, + setNeoRels, + setOpenGraphView, + setViewPoint + ); + }; + const columns = useMemo( () => [ { @@ -98,7 +116,13 @@ export default function DeletePopUpForOrphanNodes({ cell: (info) => { return (
        - {info.getValue()} + handleOrphanNodeClick(info.row.id, 'chatInfoView')} + title={info.getValue()} + > + {info.getValue()} +
        ); }, @@ -190,94 +214,105 @@ export default function DeletePopUpForOrphanNodes({ }; return ( -
        - {showDeletePopUp && ( - setshowDeletePopUp(false)} - loading={loading} - view='settingsView' - /> - )} + <>
        - - - - Orphan Nodes Deletion (100 nodes per batch) - - {totalOrphanNodes > 0 && ( + {showDeletePopUp && ( + setshowDeletePopUp(false)} + loading={loading} + view='settingsView' + /> + )} +
        + + - Total Nodes: {totalOrphanNodes} + Orphan Nodes Deletion (100 nodes per batch) - )} - - - - This feature helps improve the accuracy of your knowledge graph by identifying and removing entities that - are not connected to any other information. These "lonely" entities can be remnants of past analyses or - errors in data processing. By removing them, we can create a cleaner and more efficient knowledge graph - that leads to more relevant and informative responses. - + {totalOrphanNodes > 0 && ( + + Total Nodes: {totalOrphanNodes} + + )} + + + + This feature helps improve the accuracy of your knowledge graph by identifying and removing entities + that are not connected to any other information. These "lonely" entities can be remnants of past + analyses or errors in data processing. By removing them, we can create a cleaner and more efficient + knowledge graph that leads to more relevant and informative responses. + + +
        + , + PaginationNumericButton: ({ isSelected, innerProps, ...restProps }) => { + return ( + + ); + }, + }} + /> + + setshowDeletePopUp(true)} + size='large' + loading={loading} + text={ + isLoading + ? 'Fetching Orphan Nodes' + : !isLoading && !orphanNodes.length + ? 'No Nodes Found' + : !table.getSelectedRowModel().rows.length + ? 'No Nodes Selected' + : `Delete Selected Nodes (${table.getSelectedRowModel().rows.length})` + } + label='Orphan Node deletion button' + disabled={!table.getSelectedRowModel().rows.length} + placement='top' + > + {selectedFilesCheck} +
        - , - PaginationNumericButton: ({ isSelected, innerProps, ...restProps }) => { - return ( - - ); - }, - }} - /> - - setshowDeletePopUp(true)} - size='large' - loading={loading} - text={ - isLoading - ? 'Fetching Orphan Nodes' - : !isLoading && !orphanNodes.length - ? 'No Nodes Found' - : !table.getSelectedRowModel().rows.length - ? 'No Nodes Selected' - : `Delete Selected Nodes (${table.getSelectedRowModel().rows.length})` - } - label='Orphan Node deletion button' - disabled={!table.getSelectedRowModel().rows.length} - placement='top' - > - {selectedFilesCheck} - - -
        + {openGraphView && ( + + )} + ); } diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/EnitityExtraction/EntityExtractionSetting.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/EnitityExtraction/EntityExtractionSetting.tsx index 8a7362d26..e5e0bc033 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/EnitityExtraction/EntityExtractionSetting.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/EnitityExtraction/EntityExtractionSetting.tsx @@ -244,6 +244,26 @@ export default function EntityExtractionSetting({ onClose(); } }; + const handleApply = () => { + setIsSchema(true); + localStorage.setItem('isSchema', JSON.stringify(true)); + showNormalToast(`Successfully Applied the Schema settings`); + if (view === 'Dialog' && onClose != undefined) { + onClose(); + } + localStorage.setItem( + 'selectedNodeLabels', + JSON.stringify({ db: userCredentials?.uri, selectedOptions: selectedNodes }) + ); + localStorage.setItem( + 'selectedRelationshipLabels', + JSON.stringify({ db: userCredentials?.uri, selectedOptions: selectedRels }) + ); + localStorage.setItem( + 'selectedSchemas', + JSON.stringify({ db: userCredentials?.uri, selectedOptions: selectedSchemas }) + ); + }; // Load selectedSchemas from local storage on mount useEffect(() => { @@ -297,9 +317,8 @@ export default function EntityExtractionSetting({ options: nodeLabelOptions, onChange: onChangenodes, value: selectedNodes, - classNamePrefix: `${ - isTablet ? 'tablet_entity_extraction_Tab_node_label' : 'entity_extraction_Tab_node_label' - }`, + classNamePrefix: `${isTablet ? 'tablet_entity_extraction_Tab_node_label' : 'entity_extraction_Tab_node_label' + }`, }} type='creatable' /> @@ -313,9 +332,8 @@ export default function EntityExtractionSetting({ options: relationshipTypeOptions, onChange: onChangerels, value: selectedRels, - classNamePrefix: `${ - isTablet ? 'tablet_entity_extraction_Tab_relationship_label' : 'entity_extraction_Tab_relationship_label' - }`, + classNamePrefix: `${isTablet ? 'tablet_entity_extraction_Tab_relationship_label' : 'entity_extraction_Tab_relationship_label' + }`, }} type='creatable' /> @@ -372,6 +390,15 @@ export default function EntityExtractionSetting({ {buttonCaptions.clearSettings} )} + + {buttonCaptions.applyGraphSchema} +
    diff --git a/frontend/src/services/GraphQuery.ts b/frontend/src/services/GraphQuery.ts index f792f4aec..d9277a504 100644 --- a/frontend/src/services/GraphQuery.ts +++ b/frontend/src/services/GraphQuery.ts @@ -1,7 +1,7 @@ import { UserCredentials } from '../types'; import api from '../API/Index'; -const graphQueryAPI = async ( +export const graphQueryAPI = async ( userCredentials: UserCredentials, query_type: string, document_names: (string | undefined)[] | undefined @@ -26,4 +26,24 @@ const graphQueryAPI = async ( throw error; } }; -export default graphQueryAPI; + +export const getNeighbors = async (userCredentials: UserCredentials, elementId: string) => { + try { + const formData = new FormData(); + formData.append('uri', userCredentials?.uri ?? ''); + formData.append('database', userCredentials?.database ?? ''); + formData.append('userName', userCredentials?.userName ?? ''); + formData.append('password', userCredentials?.password ?? ''); + formData.append('elementId', elementId); + + const response = await api.post(`/get_neighbours`, formData, { + headers: { + 'Content-Type': 'multipart/form-data', + }, + }); + return response; + } catch (error) { + console.log('Error Posting the Question:', error); + throw error; + } +}; diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 0f8f913d3..6e33515d9 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -517,6 +517,7 @@ export type Community = { level: number; community_rank: number; score?: number; + element_id: string; }; export type GroupedEntity = { texts: Set; @@ -556,6 +557,7 @@ export interface Chunk { fileSource: string; score?: string; fileType: string; + element_id: string; } export interface SpeechSynthesisProps { @@ -610,6 +612,18 @@ export interface ExtendedNode extends Node { }; } +export interface NeoNode { + element_id: string; + labels: string[]; + properties: Record; +} +export interface NeoRelationship { + element_id: string; + start_node_element_id: string; + end_node_element_id: string; + type: string; +} + export interface ExtendedRelationship extends Relationship { count?: number; } @@ -657,6 +671,9 @@ export interface S3File { export interface GraphViewButtonProps { nodeValues?: ExtendedNode[]; relationshipValues?: ExtendedRelationship[]; + fill?: 'text' | 'filled' | 'outlined'; + label: string; + viewType: string; } export interface DrawerChatbotProps { isExpanded: boolean; @@ -712,6 +729,9 @@ export type CommunitiesProps = { loading: boolean; communities: Community[]; mode: string; + + // nodeValues: ExtendedNode[]; + // relationshipValues: ExtendedRelationship[]; }; export interface entity { @@ -804,3 +824,15 @@ export type GraphPropertiesPanelProps = { inspectedItem: BasicNode | BasicRelationship; newScheme: Scheme; }; + +export interface GraphViewHandlerProps { + nodeValues?: ExtendedNode[]; + relationshipValues?: ExtendedRelationship[]; + fill?: 'text' | 'filled' | 'outlined'; + label?: string; + viewType?: string; + buttonLabel: string; + graphonly_entities?: []; + entityInfo?: Entity[]; + mode?: string; +} diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index 971227724..bd5890c91 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -112,6 +112,7 @@ export const tooltips = { clearChat: 'Clear Chat History', continue: 'Continue', clearGraphSettings: 'Clear configured Graph Schema', + applySettings:'Apply Graph Schema' }; export const buttonCaptions = { @@ -135,6 +136,7 @@ export const buttonCaptions = { continueSettings: 'Continue', clearSettings: 'Clear Schema', ask: 'Ask', + applyGraphSchema:'Apply' }; export const POST_PROCESSING_JOBS: { title: string; description: string }[] = [ From 6c6da261770a5603150313990a158d57f208eb92 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Fri, 18 Oct 2024 17:56:04 +0530 Subject: [PATCH 185/292] added error message for doc retriver (#807) --- backend/score.py | 3 +-- backend/src/QA_integration.py | 5 +++-- backend/src/communities.py | 5 +++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/backend/score.py b/backend/score.py index 7940815b2..130cd1af2 100644 --- a/backend/score.py +++ b/backend/score.py @@ -290,8 +290,7 @@ async def post_processing(uri=Form(), userName=Form(), password=Form(), database logging.info(f'Entity Embeddings created') if "enable_communities" in tasks: - model = "openai_gpt_4o" - await asyncio.to_thread(create_communities, uri, userName, password, database,model) + await asyncio.to_thread(create_communities, uri, userName, password, database) josn_obj = {'api_name': 'post_processing/create_communities', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} logging.info(f'created communities') diff --git a/backend/src/QA_integration.py b/backend/src/QA_integration.py index cf7c74f6d..27849fc20 100644 --- a/backend/src/QA_integration.py +++ b/backend/src/QA_integration.py @@ -276,8 +276,9 @@ def retrieve_documents(doc_retriever, messages): logging.info(f"Documents retrieved in {doc_retrieval_time:.2f} seconds") except Exception as e: - logging.error(f"Error retrieving documents: {e}") - raise + error_message = f"Error retrieving documents: {str(e)}" + logging.error(error_message) + raise RuntimeError(error_message) return docs,transformed_question diff --git a/backend/src/communities.py b/backend/src/communities.py index 1b19c689b..d1130150c 100644 --- a/backend/src/communities.py +++ b/backend/src/communities.py @@ -13,7 +13,8 @@ NODE_PROJECTION_ENTITY = "__Entity__" MAX_WORKERS = 10 MAX_COMMUNITY_LEVELS = 3 -MIN_COMMUNITY_SIZE = 1 +MIN_COMMUNITY_SIZE = 1 +COMMUNITY_CREATION_DEFAULT_MODEL = "openai_gpt_4o" CREATE_COMMUNITY_GRAPH_PROJECTION = """ @@ -466,7 +467,7 @@ def clear_communities(gds): raise -def create_communities(uri, username, password, database,model): +def create_communities(uri, username, password, database,model=COMMUNITY_CREATION_DEFAULT_MODEL): try: gds = get_gds_driver(uri, username, password, database) clear_communities(gds) From 3d587f0bab625fcfe53e0621d626a23f3ac6804a Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Fri, 18 Oct 2024 18:04:59 +0530 Subject: [PATCH 186/292] copy row (#803) * copy row * column for copy * column copy --- frontend/src/components/FileTable.tsx | 63 ++++++++++++--------------- 1 file changed, 29 insertions(+), 34 deletions(-) diff --git a/frontend/src/components/FileTable.tsx b/frontend/src/components/FileTable.tsx index e5aa5ada4..ad0f7bc19 100644 --- a/frontend/src/components/FileTable.tsx +++ b/frontend/src/components/FileTable.tsx @@ -71,6 +71,7 @@ const FileTable = forwardRef((props, ref) => { const skipPageResetRef = useRef(false); const [_, copy] = useCopyToClipboard(); const { colorMode } = useContext(ThemeWrapperContext); + const [copyRow, setCopyRow] = useState(false); const tableRef = useRef(null); @@ -83,8 +84,13 @@ const FileTable = forwardRef((props, ref) => { } ); - const handleCopy = (message: string) => { - copy(message); + const handleCopy = (rowData: any) => { + const rowString = JSON.stringify(rowData, null, 2); + copy(rowString); + setCopyRow(true); + setTimeout(() => { + setCopyRow(false); + }, 5000); }; const columns = useMemo( () => [ @@ -154,18 +160,14 @@ const FileTable = forwardRef((props, ref) => { cell: (info) => { if (info.getValue() != 'Processing') { return ( - -
    - - - {info.getValue()} - - {(info.getValue() === 'Completed' || - info.getValue() === 'Failed' || - (info.getValue() === 'Cancelled' && !isReadOnlyUser)) && ( +
    + + {info.getValue()} + {(info.getValue() === 'Completed' || info.getValue() === 'Failed' || info.getValue() === 'Cancelled') && + !isReadOnlyUser && ( ((props, ref) => { )} -
    - - {info.row.original?.status === 'Failed' && ( - - handleCopy(info.row.original?.errorMessage ?? '')} - > - - - - )} - +
    ); } else if (info.getValue() === 'Processing' && info.row.original.processingProgress === undefined) { return ( @@ -531,9 +515,20 @@ const FileTable = forwardRef((props, ref) => { > + handleCopy(info.row.original)} + > + + ), - header: () => View, + header: () => Actions, footer: (info) => info.column.id, }), ], From 845bfb75d9fde846f9eab9b3284bc2c0a4f20dc1 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Fri, 18 Oct 2024 18:12:09 +0530 Subject: [PATCH 187/292] Raga's Evaluation For Multi Modes (#806) * Updatedmodels for ragas eval * context utilization metrics removed * updated supported llms for ragas * removed context utilization * Implemented Parallel API * multi api calls error resolved * MultiMode Metrics * Fix: Metric Evalution For Single Mode * multi modes ragas evaluation * api payload changes * metric api output format changed * multi mode ragas changes * removed pre process dataset * api response changes * Multimode metrics api integration * nan error for no answer resolved * QA integration changes --------- Co-authored-by: kaustubh-darekar --- backend/score.py | 42 +++-- backend/src/QA_integration.py | 2 +- backend/src/ragas_eval.py | 78 ++------- .../src/components/ChatBot/ChatInfoModal.tsx | 156 ++++++++++++------ frontend/src/components/ChatBot/Chatbot.tsx | 74 +++++---- .../src/components/ChatBot/MetricsTab.tsx | 22 ++- .../components/ChatBot/MultiModeMetrics.tsx | 116 +++++++++++++ frontend/src/services/GetRagasMetric.ts | 13 +- frontend/src/types.ts | 36 +++- frontend/src/utils/Constants.ts | 15 +- frontend/src/utils/Utils.ts | 11 ++ 11 files changed, 378 insertions(+), 187 deletions(-) create mode 100644 frontend/src/components/ChatBot/MultiModeMetrics.tsx diff --git a/backend/score.py b/backend/score.py index 130cd1af2..d78a13746 100644 --- a/backend/score.py +++ b/backend/score.py @@ -786,24 +786,34 @@ async def retry_processing(uri=Form(), userName=Form(), password=Form(), databas gc.collect() @app.post('/metric') -async def calculate_metric(question=Form(), context=Form(), answer=Form(), model=Form()): +async def calculate_metric(question: str = Form(), + context: str = Form(), + answer: str = Form(), + model: str = Form(), + mode: str = Form()): try: - payload_json_obj = {'api_name':'metric', 'context':context, 'answer':answer, 'model':model, 'logging_time': formatted_time(datetime.now(timezone.utc))} - logger.log_struct(payload_json_obj, "INFO") - result = await asyncio.to_thread(get_ragas_metrics, question, context, answer, model) - if result is None or "error" in result: - return create_api_response( - 'Failed', - message='Failed to calculate evaluation metrics.', - error=result.get("error", "Ragas evaluation returned null") - ) - return create_api_response('Success', data=result) + context_list = [str(item).strip() for item in json.loads(context)] if context else [] + answer_list = [str(item).strip() for item in json.loads(answer)] if answer else [] + mode_list = [str(item).strip() for item in json.loads(mode)] if mode else [] + + result = await asyncio.to_thread( + get_ragas_metrics, question, context_list, answer_list, model + ) + if result is None or "error" in result: + return create_api_response( + 'Failed', + message='Failed to calculate evaluation metrics.', + error=result.get("error", "Ragas evaluation returned null") + ) + data = {mode: {metric: result[metric][i] for metric in result} for i, mode in enumerate(mode_list)} + return create_api_response('Success', data=data) except Exception as e: - job_status = "Failed" - message = "Error while calculating evaluation metrics" - error_message = str(e) - logging.exception(f'{error_message}') - return create_api_response(job_status, message=message, error=error_message) + logging.exception(f"Error while calculating evaluation metrics: {e}") + return create_api_response( + 'Failed', + message="Error while calculating evaluation metrics", + error=str(e) + ) finally: gc.collect() diff --git a/backend/src/QA_integration.py b/backend/src/QA_integration.py index 27849fc20..468069531 100644 --- a/backend/src/QA_integration.py +++ b/backend/src/QA_integration.py @@ -435,7 +435,7 @@ def process_chat_response(messages, history, question, model, graph, document_na total_tokens = 0 formatted_docs = "" - question = transformed_question if transformed_question else question + # question = transformed_question if transformed_question else question # metrics = get_ragas_metrics(question,formatted_docs,content) # print(metrics) diff --git a/backend/src/ragas_eval.py b/backend/src/ragas_eval.py index e177b6d61..a5ce06b5b 100644 --- a/backend/src/ragas_eval.py +++ b/backend/src/ragas_eval.py @@ -1,88 +1,44 @@ import os import logging import time -from typing import Dict, Tuple, Optional -import boto3 +from src.llm import get_llm from datasets import Dataset from dotenv import load_dotenv -from langchain_anthropic import ChatAnthropic -from langchain_aws import ChatBedrock -from langchain_community.chat_models import ChatOllama -from langchain_experimental.graph_transformers.diffbot import DiffbotGraphTransformer -from langchain_fireworks import ChatFireworks -from langchain_google_vertexai import ( - ChatVertexAI, - HarmBlockThreshold, - HarmCategory, -) -from langchain_groq import ChatGroq -from langchain_openai import AzureChatOpenAI, ChatOpenAI from ragas import evaluate -from ragas.metrics import answer_relevancy, context_utilization, faithfulness +from ragas.metrics import answer_relevancy, faithfulness from src.shared.common_fn import load_embedding_model - load_dotenv() -RAGAS_MODEL_VERSIONS = { - "openai_gpt_3.5": "gpt-3.5-turbo-16k", - "openai_gpt_4": "gpt-4-turbo-2024-04-09", - "openai_gpt_4o_mini": "gpt-4o-mini-2024-07-18", - "openai_gpt_4o": "gpt-4o-mini-2024-07-18", - "groq_llama3_70b": "groq_llama3_70b", -} EMBEDDING_MODEL = os.getenv("EMBEDDING_MODEL") EMBEDDING_FUNCTION, _ = load_embedding_model(EMBEDDING_MODEL) - -def get_ragas_llm(model: str) -> Tuple[object, str]: - """Retrieves the specified language model. Improved error handling and structure.""" - env_key = f"LLM_MODEL_CONFIG_{model}" - env_value = os.environ.get(env_key) - logging.info(f"Loading model configuration: {env_key}") - try: - if "openai" in model: - model_name = RAGAS_MODEL_VERSIONS[model] - llm = ChatOpenAI( - api_key=os.environ.get("OPENAI_API_KEY"), model=model_name, temperature=0 - ) - elif "groq" in model: - model_name, base_url, api_key = env_value.split(",") - llm = ChatGroq(api_key=api_key, model_name=model_name, temperature=0) - else: - raise ValueError(f"Unsupported model for evaluation: {model}") - - logging.info(f"Model loaded - Model Version: {model}") - return llm, model_name - except (ValueError, KeyError) as e: - logging.error(f"Error loading LLM: {e}") - raise - - -def get_ragas_metrics( - question: str, context: str, answer: str, model: str -) -> Optional[Dict[str, float]]: +def get_ragas_metrics(question: str, context: list, answer: list, model: str): """Calculates RAGAS metrics.""" try: start_time = time.time() dataset = Dataset.from_dict( - {"question": [question], "answer": [answer], "contexts": [[context]]} + {"question": [question] * len(answer), "answer": answer, "contexts": [[ctx] for ctx in context]} ) - logging.info("Dataset created successfully.") - - llm, model_name = get_ragas_llm(model=model) + logging.info("Evaluation dataset created successfully.") + if ("diffbot" in model) or ("ollama" in model): + raise ValueError(f"Unsupported model for evaluation: {model}") + else: + llm, model_name = get_llm(model=model) + logging.info(f"Evaluating with model: {model_name}") - + score = evaluate( dataset=dataset, - metrics=[faithfulness, answer_relevancy, context_utilization], + metrics=[faithfulness, answer_relevancy], llm=llm, embeddings=EMBEDDING_FUNCTION, ) - + score_dict = ( - score.to_pandas()[["faithfulness", "answer_relevancy", "context_utilization"]] + score.to_pandas()[["faithfulness", "answer_relevancy"]] + .fillna(0) .round(4) - .to_dict(orient="records")[0] + .to_dict(orient="list") ) end_time = time.time() logging.info(f"Evaluation completed in: {end_time - start_time:.2f} seconds") @@ -90,7 +46,7 @@ def get_ragas_metrics( except ValueError as e: if "Unsupported model for evaluation" in str(e): logging.error(f"Unsupported model error: {e}") - return {"error": str(e)} # Return the specific error message as a dictionary + return {"error": str(e)} logging.exception(f"ValueError during metrics evaluation: {e}") return {"error": str(e)} except Exception as e: diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index 266bf98ac..0263f00e6 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -13,7 +13,7 @@ import { import { DocumentDuplicateIconOutline, ClipboardDocumentCheckIconOutline } from '@neo4j-ndl/react/icons'; import '../../styling/info.css'; import Neo4jRetrievalLogo from '../../assets/images/Neo4jRetrievalLogo.png'; -import { Entity, ExtendedNode, UserCredentials, chatInfoMessage } from '../../types'; +import { ExtendedNode, UserCredentials, chatInfoMessage, multimodelmetric } from '../../types'; import { useContext, useEffect, useMemo, useState } from 'react'; import GraphViewButton from '../Graph/GraphViewButton'; import { chunkEntitiesAPI } from '../../services/ChunkEntitiesInfo'; @@ -29,7 +29,8 @@ import { Relationship } from '@neo4j-nvl/base'; import { getChatMetrics } from '../../services/GetRagasMetric'; import MetricsTab from './MetricsTab'; import { Stack } from '@mui/material'; -import { capitalizeWithUnderscore } from '../../utils/Utils'; +import { capitalizeWithUnderscore, getNodes } from '../../utils/Utils'; +import MultiModeMetrics from './MultiModeMetrics'; const ChatInfoModal: React.FC = ({ sources, @@ -46,14 +47,6 @@ const ChatInfoModal: React.FC = ({ metriccontexts, metricquestion, metricmodel, - saveNodes, - saveChunks, - saveChatRelationships, - saveCommunities, - saveInfoEntitites, - saveMetrics, - toggleInfoLoading, - toggleMetricsLoading, nodes, chunks, infoEntities, @@ -62,6 +55,16 @@ const ChatInfoModal: React.FC = ({ relationships, infoLoading, metricsLoading, + activeChatmodes, + metricError, + saveNodes, + saveChunks, + saveChatRelationships, + saveCommunities, + saveInfoEntitites, + saveMetrics, + toggleInfoLoading, + toggleMetricsLoading, }) => { const { breakpoints } = tokens; const isTablet = useMediaQuery(`(min-width:${breakpoints.xs}) and (max-width: ${breakpoints.lg})`); @@ -73,6 +76,8 @@ const ChatInfoModal: React.FC = ({ const [, copy] = useCopyToClipboard(); const [copiedText, setcopiedText] = useState(false); const [showMetricsTable, setShowMetricsTable] = useState(Boolean(metricDetails)); + const [multiModelMetrics, setMultiModelMetrics] = useState([]); + const [multiModeError, setMultiModeError] = useState(''); console.log('node', nodeDetails); @@ -126,32 +131,11 @@ const ChatInfoModal: React.FC = ({ .filter((rel: any) => nodeIds.has(rel.end_node_element_id) && nodeIds.has(rel.start_node_element_id)); const communitiesData = response?.data?.data?.community_data; const chunksData = response?.data?.data?.chunk_data; - - saveInfoEntitites( - nodesData.map((n: Entity) => { - if (!n.labels.length && mode === chatModeLables.entity_vector) { - return { - ...n, - labels: ['Entity'], - }; - } - return n; - }) - ); - saveNodes( - nodesData.map((n: ExtendedNode) => { - if (!n.labels.length && mode === chatModeLables.entity_vector) { - return { - ...n, - labels: ['Entity'], - }; - } - return n ?? []; - }) - ); + saveInfoEntitites(getNodes(nodesData, mode)); + saveNodes(getNodes(nodesData, mode)); saveChatRelationships(relationshipsData ?? []); saveCommunities( - (communitiesData || []) + (communitiesData ?? []) .map((community: { element_id: string }) => { const communityScore = nodeDetails?.communitydetails?.find( (c: { id: string }) => c.id === community.element_id @@ -163,7 +147,6 @@ const ChatInfoModal: React.FC = ({ }) .sort((a: any, b: any) => b.score - a.score) ); - saveChunks( chunksData .map((chunk: any) => { @@ -184,29 +167,77 @@ const ChatInfoModal: React.FC = ({ } () => { setcopiedText(false); - toggleMetricsLoading(); + if (metricsLoading) { + toggleMetricsLoading(); + } + setMultiModelMetrics([]); }; - }, [nodeDetails, mode, error]); + }, [nodeDetails, mode, error, metricsLoading]); const onChangeTabs = (tabId: number) => { setActiveTab(tabId); }; const loadMetrics = async () => { - setShowMetricsTable(true); - try { - toggleMetricsLoading(); - const response = await getChatMetrics(metricquestion, metriccontexts, metricanswer, metricmodel); - toggleMetricsLoading(); - if (response.data.status === 'Success') { - saveMetrics({ ...response.data.data, error: '' }); + if (activeChatmodes) { + if (Object.keys(activeChatmodes).length <= 1) { + setShowMetricsTable(true); + const defaultMode = Object.keys(activeChatmodes)[0]; + try { + toggleMetricsLoading(); + const response = await getChatMetrics(metricquestion, [metriccontexts], [metricanswer], metricmodel, [ + defaultMode, + ]); + toggleMetricsLoading(); + if (response.data.status === 'Success') { + const data = response; + saveMetrics(data.data.data[defaultMode]); + } else { + throw new Error(response.data.error); + } + } catch (error) { + if (error instanceof Error) { + toggleMetricsLoading(); + console.log('Error in getting chat metrics', error); + saveMetrics({ faithfulness: 0, answer_relevancy: 0, error: error.message }); + } + } } else { - throw new Error(response.data.error); - } - } catch (error) { - if (error instanceof Error) { + setShowMetricsTable(true); toggleMetricsLoading(); - console.log('Error in getting chat metrics', error); - saveMetrics({ error: error.message, faithfulness: 0, answer_relevancy: 0, context_utilization: 0 }); + const contextarray = Object.values(activeChatmodes).map((r) => { + return r.metric_contexts; + }); + const answerarray = Object.values(activeChatmodes).map((r) => { + return r.metric_answer; + }); + const modesarray = Object.keys(activeChatmodes).map((mode) => { + return mode; + }); + try { + const responses = await getChatMetrics( + metricquestion, + contextarray as string[], + answerarray as string[], + metricmodel, + modesarray + ); + toggleMetricsLoading(); + if (responses.data.status === 'Success') { + const modewisedata = responses.data.data; + const metricsdata = Object.entries(modewisedata).map(([mode, scores]) => { + return { mode, answer_relevancy: scores.answer_relevancy, faithfulness: scores.faithfulness }; + }); + setMultiModelMetrics(metricsdata); + } else { + throw new Error(responses.data.error); + } + } catch (error) { + toggleMetricsLoading(); + console.log('Error in getting chat metrics', error); + if (error instanceof Error) { + setMultiModeError(error.message); + } + } } } }; @@ -303,13 +334,18 @@ const ChatInfoModal: React.FC = ({ Answer Relevancy: Determines How well the answer addresses the user's question. - - Context Utilization: Determines How effectively the system uses the - retrieved information to answer thequestion. - - {showMetricsTable && } + {showMetricsTable && activeChatmodes != null && Object.keys(activeChatmodes).length > 1 && ( + + )} + {showMetricsTable && activeChatmodes != null && Object.keys(activeChatmodes).length <= 1 && ( + + )} {!metricDetails && ( )} + {!multiModelMetrics && ( + + )} diff --git a/frontend/src/components/ChatBot/Chatbot.tsx b/frontend/src/components/ChatBot/Chatbot.tsx index a1eeb35ef..1f7049f0d 100644 --- a/frontend/src/components/ChatBot/Chatbot.tsx +++ b/frontend/src/components/ChatBot/Chatbot.tsx @@ -22,9 +22,9 @@ import { ExtendedNode, ExtendedRelationship, Messages, - MetricsState, ResponseMode, UserCredentials, + metricstate, nodeDetailsProps, } from '../../types'; import { useCredentials } from '../../context/UserCredentials'; @@ -74,7 +74,7 @@ const Chatbot: FC = (props) => { const [nodes, setNodes] = useState([]); const [relationships, setRelationships] = useState([]); const [chunks, setChunks] = useState([]); - const [metricDetails, setMetricDetails] = useState(null); + const [metricDetails, setMetricDetails] = useState(null); const [infoEntities, setInfoEntities] = useState([]); const [communities, setCommunities] = useState([]); const [infoLoading, toggleInfoLoading] = useReducer((s) => !s, false); @@ -112,7 +112,7 @@ const Chatbot: FC = (props) => { const saveChunks = (chatChunks: Chunk[]) => { setChunks(chatChunks); }; - const saveMetrics = (metricInfo: MetricsState) => { + const saveMetrics = (metricInfo: metricstate) => { setMetricDetails(metricInfo); }; const saveCommunities = (chatCommunities: Community[]) => { @@ -269,15 +269,15 @@ const Chatbot: FC = (props) => { console.error(`API call failed for mode ${mode}:`, result.reason); setListMessages((prev) => prev.map((msg) => - (msg.id === chatbotMessageId - ? { - ...msg, - modes: { - ...msg.modes, - [mode]: { message: 'Failed to fetch response for this mode.', error: result.reason }, - }, - } - : msg) + (msg.id === chatbotMessageId + ? { + ...msg, + modes: { + ...msg.modes, + [mode]: { message: 'Failed to fetch response for this mode.', error: result.reason }, + }, + } + : msg) ) ); } @@ -290,19 +290,19 @@ const Chatbot: FC = (props) => { if (error instanceof Error) { setListMessages((prev) => prev.map((msg) => - (msg.id === chatbotMessageId - ? { - ...msg, - isLoading: false, - isTyping: false, - modes: { - [chatModes[0]]: { - message: 'An error occurred while processing your request.', - error: error.message, - }, - }, - } - : msg) + (msg.id === chatbotMessageId + ? { + ...msg, + isLoading: false, + isTyping: false, + modes: { + [chatModes[0]]: { + message: 'An error occurred while processing your request.', + error: error.message, + }, + }, + } + : msg) ) ); } @@ -391,7 +391,10 @@ const Chatbot: FC = (props) => { setMetricContext(currentMode.metric_contexts ?? ''); setMetricAnswer(currentMode.metric_answer ?? ''); setActiveChat(chat); - if ((previousActiveChat != null && chat.id != previousActiveChat?.id) || (previousActiveChat != null && chat.currentMode != previousActiveChat.currentMode)) { + if ( + (previousActiveChat != null && chat.id != previousActiveChat?.id) || + (previousActiveChat != null && chat.currentMode != previousActiveChat.currentMode) + ) { setNodes([]); setChunks([]); setInfoEntities([]); @@ -450,12 +453,14 @@ const Chatbot: FC = (props) => {
    {chat.modes[chat.currentMode]?.message || ''} @@ -539,8 +544,9 @@ const Chatbot: FC = (props) => {
    = (props) => { infoEntities={infoEntities} relationships={relationships} chunks={chunks} - metricDetails={metricDetails} + metricDetails={activeChat != undefined && metricDetails != null ? metricDetails : undefined} + metricError={activeChat != undefined && metricDetails != null ? (metricDetails.error as string) : ''} communities={communities} infoLoading={infoLoading} metricsLoading={metricsLoading} @@ -641,6 +648,7 @@ const Chatbot: FC = (props) => { saveNodes={saveNodes} toggleInfoLoading={toggleInfoLoading} toggleMetricsLoading={toggleMetricsLoading} + activeChatmodes={activeChat?.modes} /> diff --git a/frontend/src/components/ChatBot/MetricsTab.tsx b/frontend/src/components/ChatBot/MetricsTab.tsx index 17b5e67ae..55d37db4c 100644 --- a/frontend/src/components/ChatBot/MetricsTab.tsx +++ b/frontend/src/components/ChatBot/MetricsTab.tsx @@ -1,5 +1,4 @@ import { Banner, Box, DataGrid, DataGridComponents, Typography } from '@neo4j-ndl/react'; -import { MetricsState } from '../../types'; import { memo, useMemo, useRef } from 'react'; import { useReactTable, @@ -13,9 +12,16 @@ import { capitalize } from '../../utils/Utils'; function MetricsTab({ metricsLoading, metricDetails, + error, }: { metricsLoading: boolean; - metricDetails: MetricsState | null; + metricDetails: + | { + faithfulness: number; + answer_relevancy: number; + } + | undefined; + error: string; }) { const columnHelper = createColumnHelper<{ metric: string; score: number }>(); const tableRef = useRef(null); @@ -53,11 +59,9 @@ function MetricsTab({ const table = useReactTable({ data: metricDetails != null && !metricsLoading - ? Object.entries(metricDetails) - .slice(0, Object.keys(metricDetails).length - 1) - .map(([key, value]) => { - return { metric: key, score: value }; - }) + ? Object.entries(metricDetails).map(([key, value]) => { + return { metric: key, score: value }; + }) : [], columns, getCoreRowModel: getCoreRowModel(), @@ -72,8 +76,8 @@ function MetricsTab({ }); return ( - {metricDetails != null && metricDetails?.error?.trim() != '' ? ( - {metricDetails?.error} + {error != undefined && error?.trim() != '' ? ( + {error} ) : ( (null); + + const columnHelper = createColumnHelper(); + const columns = useMemo( + () => [ + columnHelper.accessor((row) => row.mode, { + id: 'Mode', + cell: (info) => { + const metric = info.getValue(); + const capitilizedMetric = metric.includes('_') + ? metric + .split('_') + .map((w) => capitalize(w)) + .join(' ') + : capitalize(metric); + return ( +
    + {capitilizedMetric} +
    + ); + }, + header: () => Mode, + footer: (info) => info.column.id, + }), + columnHelper.accessor((row) => row.answer_relevancy, { + id: 'Answer Relevancy', + cell: (info) => { + return {info.getValue().toFixed(2)}; + }, + header: () => Answer Relevancy, + }), + columnHelper.accessor((row) => row.faithfulness, { + id: 'Score', + cell: (info) => { + return {info.getValue().toFixed(2)}; + }, + header: () => Faithfulness, + }), + ], + [] + ); + const table = useReactTable({ + data, + columns, + getCoreRowModel: getCoreRowModel(), + getFilteredRowModel: getFilteredRowModel(), + getPaginationRowModel: getPaginationRowModel(), + enableGlobalFilter: false, + autoResetPageIndex: false, + enableRowSelection: true, + enableMultiRowSelection: true, + enableSorting: true, + getSortedRowModel: getSortedRowModel(), + }); + return ( + + {error?.trim() != '' ? ( + {error} + ) : ( + , + PaginationNumericButton: ({ isSelected, innerProps, ...restProps }) => { + return ( + + ); + }, + }} + /> + )} + + ); +} diff --git a/frontend/src/services/GetRagasMetric.ts b/frontend/src/services/GetRagasMetric.ts index a72c69e5d..90e365d00 100644 --- a/frontend/src/services/GetRagasMetric.ts +++ b/frontend/src/services/GetRagasMetric.ts @@ -1,12 +1,19 @@ import { MetricsResponse } from '../types'; import api from '../API/Index'; -export const getChatMetrics = async (question: string, context: string, answer: string, model: string) => { +export const getChatMetrics = async ( + question: string, + context: string[], + answer: string[], + model: string, + mode: string[] +) => { const formData = new FormData(); formData.append('question', question); - formData.append('context', `[${context}]`); - formData.append('answer', answer); + formData.append('context', JSON.stringify(context)); + formData.append('answer', JSON.stringify(answer)); formData.append('model', model); + formData.append('mode', JSON.stringify(mode)); try { const response = await api.post(`/metric`, formData); return response; diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 6e33515d9..39f9a041c 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -410,11 +410,18 @@ export interface duplicateNodesData extends Partial { export interface OrphanNodeResponse extends Partial { data: orphanNodeProps[]; } -export type metricdetails = { +export type metricstate = { faithfulness: number; answer_relevancy: number; - context_utilization: number; + error?: string; }; +export type metricdetails = Record; + +export interface multimodelmetric { + mode: string; + answer_relevancy: number; + faithfulness: number; +} export interface MetricsResponse extends Omit { data: metricdetails; } @@ -430,10 +437,6 @@ export interface SourceListServerData { message?: string; } -export interface MetricsState extends metricdetails { - error?: string; -} - export interface chatInfoMessage extends Partial { sources: string[]; model: string; @@ -452,16 +455,27 @@ export interface chatInfoMessage extends Partial { nodes: ExtendedNode[]; relationships: ExtendedRelationship[]; chunks: Chunk[]; - metricDetails: MetricsState | null; + metricDetails: + | { + faithfulness: number; + answer_relevancy: number; + } + | undefined; + metricError: string; infoEntities: Entity[]; communities: Community[]; infoLoading: boolean; metricsLoading: boolean; + activeChatmodes: + | { + [key: string]: ResponseMode; + } + | undefined; saveInfoEntitites: (entities: Entity[]) => void; saveNodes: (chatNodes: ExtendedNode[]) => void; saveChatRelationships: (chatRels: ExtendedRelationship[]) => void; saveChunks: (chatChunks: Chunk[]) => void; - saveMetrics: (metricInfo: MetricsState) => void; + saveMetrics: (metricInfo: metricstate) => void; saveCommunities: (chatCommunities: Community[]) => void; toggleInfoLoading: React.DispatchWithoutAction; toggleMetricsLoading: React.DispatchWithoutAction; @@ -825,6 +839,11 @@ export type GraphPropertiesPanelProps = { newScheme: Scheme; }; + +export type withId = { + id: string; +}; + export interface GraphViewHandlerProps { nodeValues?: ExtendedNode[]; relationshipValues?: ExtendedRelationship[]; @@ -836,3 +855,4 @@ export interface GraphViewHandlerProps { entityInfo?: Entity[]; mode?: string; } + diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index bd5890c91..c67ef5b27 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -32,7 +32,20 @@ export const defaultLLM = llms?.includes('openai_gpt_4o') : llms?.includes('gemini_1.5_pro') ? 'gemini_1.5_pro' : 'diffbot'; -export const supportedLLmsForRagas = ['openai_gpt_3.5', 'openai_gpt_4o', 'openai_gpt_4o_mini', 'groq_llama3_70b']; +export const supportedLLmsForRagas = [ + 'openai_gpt_3.5', + 'openai_gpt_4', + 'openai_gpt_4o', + 'openai_gpt_4o_mini', + 'gemini_1.5_pro', + 'gemini_1.5_flash', + 'azure_ai_gpt_35', + 'azure_ai_gpt_4o', + 'groq_llama3_70b', + 'anthropic_claude_3_5_sonnet', + 'fireworks_llama_v3_70b', + 'bedrock_claude_3_5_sonnet', +]; export const chatModeLables = { vector: 'vector', graph: 'graph', diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index 27645ac7e..5727f33ea 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -509,3 +509,14 @@ export function downloadClickHandler( downloadLinkRef.current.click(); } } +export function getNodes(nodesData: Array, mode: string) { + return nodesData.map((n) => { + if (!n.labels.length && mode === chatModeLables.entity_vector) { + return { + ...n, + labels: ['Entity'], + }; + } + return n; + }); +} From 952291d13a910fb0cb5a14bd6d433b90ad0eed99 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Fri, 18 Oct 2024 12:53:30 +0000 Subject: [PATCH 188/292] lint fixes --- frontend/src/components/ChatBot/ChunkInfo.tsx | 2 +- frontend/src/components/FileTable.tsx | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/src/components/ChatBot/ChunkInfo.tsx b/frontend/src/components/ChatBot/ChunkInfo.tsx index 7f31cd4d5..fa8496581 100644 --- a/frontend/src/components/ChatBot/ChunkInfo.tsx +++ b/frontend/src/components/ChatBot/ChunkInfo.tsx @@ -22,7 +22,7 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { const [neoRels, setNeoRels] = useState([]); const [openGraphView, setOpenGraphView] = useState(false); const [viewPoint, setViewPoint] = useState(''); - const [loadingGraphView, setLoadingGraphView] = useState(false); + const [_, setLoadingGraphView] = useState(false); const handleChunkClick = async (elementId: string, viewMode: string) => { handleGraphNodeClick( diff --git a/frontend/src/components/FileTable.tsx b/frontend/src/components/FileTable.tsx index ad0f7bc19..6289c1adf 100644 --- a/frontend/src/components/FileTable.tsx +++ b/frontend/src/components/FileTable.tsx @@ -7,7 +7,6 @@ import { ProgressBar, StatusIndicator, TextLink, - Tip, Typography, useCopyToClipboard, } from '@neo4j-ndl/react'; From f5a5eddf8865eb0e1f461105a1c41dbaeb689361 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Mon, 21 Oct 2024 05:04:27 +0000 Subject: [PATCH 189/292] fix: multimode metrics state handling fix: lint fixes --- .../src/components/ChatBot/ChatInfoModal.tsx | 18 +++--- frontend/src/components/ChatBot/Chatbot.tsx | 10 +++ frontend/src/components/ChatBot/ChunkInfo.tsx | 2 +- .../src/components/ChatBot/EntitiesInfo.tsx | 2 +- .../src/components/ChatBot/SourcesInfo.tsx | 8 +-- frontend/src/components/ChatBot/chatInfo.ts | 64 +++++++++---------- frontend/src/components/Dropdown.tsx | 4 +- .../components/Graph/GraphPropertiesTable.tsx | 1 - .../Deduplication/index.tsx | 2 +- .../EntityExtractionSetting.tsx | 10 +-- frontend/src/types.ts | 4 +- frontend/src/utils/Constants.ts | 4 +- frontend/src/utils/Utils.ts | 1 - 13 files changed, 70 insertions(+), 60 deletions(-) diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index 0263f00e6..a8e612ca5 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -13,7 +13,7 @@ import { import { DocumentDuplicateIconOutline, ClipboardDocumentCheckIconOutline } from '@neo4j-ndl/react/icons'; import '../../styling/info.css'; import Neo4jRetrievalLogo from '../../assets/images/Neo4jRetrievalLogo.png'; -import { ExtendedNode, UserCredentials, chatInfoMessage, multimodelmetric } from '../../types'; +import { ExtendedNode, UserCredentials, chatInfoMessage } from '../../types'; import { useContext, useEffect, useMemo, useState } from 'react'; import GraphViewButton from '../Graph/GraphViewButton'; import { chunkEntitiesAPI } from '../../services/ChunkEntitiesInfo'; @@ -57,6 +57,7 @@ const ChatInfoModal: React.FC = ({ metricsLoading, activeChatmodes, metricError, + multiModelMetrics, saveNodes, saveChunks, saveChatRelationships, @@ -65,6 +66,7 @@ const ChatInfoModal: React.FC = ({ saveMetrics, toggleInfoLoading, toggleMetricsLoading, + saveMultimodemetrics, }) => { const { breakpoints } = tokens; const isTablet = useMediaQuery(`(min-width:${breakpoints.xs}) and (max-width: ${breakpoints.lg})`); @@ -76,11 +78,8 @@ const ChatInfoModal: React.FC = ({ const [, copy] = useCopyToClipboard(); const [copiedText, setcopiedText] = useState(false); const [showMetricsTable, setShowMetricsTable] = useState(Boolean(metricDetails)); - const [multiModelMetrics, setMultiModelMetrics] = useState([]); const [multiModeError, setMultiModeError] = useState(''); - console.log('node', nodeDetails); - const actions: CypherCodeBlockProps['actions'] = useMemo( () => [ { @@ -170,7 +169,6 @@ const ChatInfoModal: React.FC = ({ if (metricsLoading) { toggleMetricsLoading(); } - setMultiModelMetrics([]); }; }, [nodeDetails, mode, error, metricsLoading]); @@ -181,7 +179,7 @@ const ChatInfoModal: React.FC = ({ if (activeChatmodes) { if (Object.keys(activeChatmodes).length <= 1) { setShowMetricsTable(true); - const defaultMode = Object.keys(activeChatmodes)[0]; + const [defaultMode] = Object.keys(activeChatmodes); try { toggleMetricsLoading(); const response = await getChatMetrics(metricquestion, [metriccontexts], [metricanswer], metricmodel, [ @@ -227,7 +225,7 @@ const ChatInfoModal: React.FC = ({ const metricsdata = Object.entries(modewisedata).map(([mode, scores]) => { return { mode, answer_relevancy: scores.answer_relevancy, faithfulness: scores.faithfulness }; }); - setMultiModelMetrics(metricsdata); + saveMultimodemetrics(metricsdata); } else { throw new Error(responses.data.error); } @@ -346,7 +344,7 @@ const ChatInfoModal: React.FC = ({ {showMetricsTable && activeChatmodes != null && Object.keys(activeChatmodes).length <= 1 && ( )} - {!metricDetails && ( + {!metricDetails && activeChatmodes != undefined && Object.keys(activeChatmodes).length <= 1 && ( )} - {!multiModelMetrics && ( + {!multiModelMetrics.length && activeChatmodes != undefined && Object.keys(activeChatmodes).length > 1 && ( )} diff --git a/frontend/src/components/ChatBot/Chatbot.tsx b/frontend/src/components/ChatBot/Chatbot.tsx index 1f7049f0d..3c1992645 100644 --- a/frontend/src/components/ChatBot/Chatbot.tsx +++ b/frontend/src/components/ChatBot/Chatbot.tsx @@ -25,6 +25,7 @@ import { ResponseMode, UserCredentials, metricstate, + multimodelmetric, nodeDetailsProps, } from '../../types'; import { useCredentials } from '../../context/UserCredentials'; @@ -81,6 +82,7 @@ const Chatbot: FC = (props) => { const [metricsLoading, toggleMetricsLoading] = useReducer((s) => !s, false); const downloadLinkRef = useRef(null); const [activeChat, setActiveChat] = useState(null); + const [multiModelMetrics, setMultiModelMetrics] = useState([]); const [_, copy] = useCopyToClipboard(); const { speak, cancel, speaking } = useSpeechSynthesis({ @@ -112,6 +114,9 @@ const Chatbot: FC = (props) => { const saveChunks = (chatChunks: Chunk[]) => { setChunks(chatChunks); }; + const saveMultimodemetrics = (metrics: multimodelmetric[]) => { + setMultiModelMetrics(metrics); + }; const saveMetrics = (metricInfo: metricstate) => { setMetricDetails(metricInfo); }; @@ -400,6 +405,9 @@ const Chatbot: FC = (props) => { setInfoEntities([]); setMetricDetails(null); } + if (previousActiveChat != null && chat.id != previousActiveChat?.id) { + setMultiModelMetrics([]); + } }, []); const speechHandler = useCallback((chat: Messages) => { @@ -648,7 +656,9 @@ const Chatbot: FC = (props) => { saveNodes={saveNodes} toggleInfoLoading={toggleInfoLoading} toggleMetricsLoading={toggleMetricsLoading} + saveMultimodemetrics={saveMultimodemetrics} activeChatmodes={activeChat?.modes} + multiModelMetrics={multiModelMetrics} /> diff --git a/frontend/src/components/ChatBot/ChunkInfo.tsx b/frontend/src/components/ChatBot/ChunkInfo.tsx index fa8496581..17083fe1e 100644 --- a/frontend/src/components/ChatBot/ChunkInfo.tsx +++ b/frontend/src/components/ChatBot/ChunkInfo.tsx @@ -24,7 +24,7 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { const [viewPoint, setViewPoint] = useState(''); const [_, setLoadingGraphView] = useState(false); - const handleChunkClick = async (elementId: string, viewMode: string) => { + const handleChunkClick = (elementId: string, viewMode: string) => { handleGraphNodeClick( userCredentials as UserCredentials, elementId, diff --git a/frontend/src/components/ChatBot/EntitiesInfo.tsx b/frontend/src/components/ChatBot/EntitiesInfo.tsx index 2b1ff3cca..80e4fdafa 100644 --- a/frontend/src/components/ChatBot/EntitiesInfo.tsx +++ b/frontend/src/components/ChatBot/EntitiesInfo.tsx @@ -43,7 +43,7 @@ const EntitiesInfo: FC = ({ loading, mode, graphonly_entities, in return Object.keys(labelCounts).sort((a, b) => labelCounts[b] - labelCounts[a]); }, [labelCounts]); - const handleEntityClick = async (elementId: string, viewMode: string) => { + const handleEntityClick = (elementId: string, viewMode: string) => { handleGraphNodeClick( userCredentials as UserCredentials, elementId, diff --git a/frontend/src/components/ChatBot/SourcesInfo.tsx b/frontend/src/components/ChatBot/SourcesInfo.tsx index 79d710fa2..35d76aefb 100644 --- a/frontend/src/components/ChatBot/SourcesInfo.tsx +++ b/frontend/src/components/ChatBot/SourcesInfo.tsx @@ -12,14 +12,14 @@ import s3logo from '../../assets/images/s3logo.png'; const filterUniqueChunks = (chunks: Chunk[]) => { const chunkSource = new Set(); - return chunks.filter(chunk => { + return chunks.filter((chunk) => { const sourceCheck = `${chunk.fileName}-${chunk.fileSource}`; if (chunkSource.has(sourceCheck)) { return false; - } else { + } chunkSource.add(sourceCheck); return true; - } + }); }; @@ -147,4 +147,4 @@ const SourcesInfo: FC = ({ loading, mode, chunks, sources }) => { ); }; -export default SourcesInfo; \ No newline at end of file +export default SourcesInfo; diff --git a/frontend/src/components/ChatBot/chatInfo.ts b/frontend/src/components/ChatBot/chatInfo.ts index 821cf69f8..c7e990ae7 100644 --- a/frontend/src/components/ChatBot/chatInfo.ts +++ b/frontend/src/components/ChatBot/chatInfo.ts @@ -2,39 +2,39 @@ import { getNeighbors } from '../../services/GraphQuery'; import { NeoNode, NeoRelationship, UserCredentials } from '../../types'; export const handleGraphNodeClick = async ( - userCredentials: UserCredentials, - elementId: string, - viewMode: string, - setNeoNodes: React.Dispatch>, - setNeoRels: React.Dispatch>, - setOpenGraphView: React.Dispatch>, - setViewPoint: React.Dispatch>, - setLoadingGraphView?: React.Dispatch> + userCredentials: UserCredentials, + elementId: string, + viewMode: string, + setNeoNodes: React.Dispatch>, + setNeoRels: React.Dispatch>, + setOpenGraphView: React.Dispatch>, + setViewPoint: React.Dispatch>, + setLoadingGraphView?: React.Dispatch> ) => { - if (setLoadingGraphView) { - setLoadingGraphView(true); + if (setLoadingGraphView) { + setLoadingGraphView(true); + } + try { + const result = await getNeighbors(userCredentials, elementId); + if (result && result.data.data.nodes.length > 0) { + let { nodes } = result.data.data; + if (viewMode === 'Chunk') { + nodes = nodes.filter((node: NeoNode) => node.labels.length === 1 && node.properties.id !== null); + } + const nodeIds = new Set(nodes.map((node: NeoNode) => node.element_id)); + const relationships = result.data.data.relationships.filter( + (rel: NeoRelationship) => nodeIds.has(rel.end_node_element_id) && nodeIds.has(rel.start_node_element_id) + ); + setNeoNodes(nodes); + setNeoRels(relationships); + setOpenGraphView(true); + setViewPoint('chatInfoView'); } - try { - const result = await getNeighbors(userCredentials, elementId); - if (result && result.data.data.nodes.length > 0) { - let { nodes } = result.data.data; - if (viewMode === 'Chunk') { - nodes = nodes.filter((node: NeoNode) => node.labels.length === 1 && node.properties.id !== null); - } - const nodeIds = new Set(nodes.map((node: NeoNode) => node.element_id)); - const relationships = result.data.data.relationships.filter( - (rel: NeoRelationship) => nodeIds.has(rel.end_node_element_id) && nodeIds.has(rel.start_node_element_id) - ); - setNeoNodes(nodes); - setNeoRels(relationships); - setOpenGraphView(true); - setViewPoint('chatInfoView'); - } - } catch (error: any) { - console.error('Error fetching neighbors:', error); - } finally { - if (setLoadingGraphView) { - setLoadingGraphView(false); - } + } catch (error: any) { + console.error('Error fetching neighbors:', error); + } finally { + if (setLoadingGraphView) { + setLoadingGraphView(false); } + } }; diff --git a/frontend/src/components/Dropdown.tsx b/frontend/src/components/Dropdown.tsx index 48188f38b..087e0d71c 100644 --- a/frontend/src/components/Dropdown.tsx +++ b/frontend/src/components/Dropdown.tsx @@ -39,7 +39,9 @@ const DropdownComponent: React.FC = ({ }; }), placeholder: placeholder || 'Select an option', - defaultValue: defaultValue ? { label: capitalize(defaultValue), value: defaultValue } : undefined, + defaultValue: defaultValue + ? { label: capitalizeWithUnderscore(defaultValue), value: defaultValue } + : undefined, menuPlacement: 'auto', isDisabled: isDisabled, value: value, diff --git a/frontend/src/components/Graph/GraphPropertiesTable.tsx b/frontend/src/components/Graph/GraphPropertiesTable.tsx index 7600ccd35..fa270455b 100644 --- a/frontend/src/components/Graph/GraphPropertiesTable.tsx +++ b/frontend/src/components/Graph/GraphPropertiesTable.tsx @@ -2,7 +2,6 @@ import { GraphLabel, Typography } from '@neo4j-ndl/react'; import { GraphPropertiesTableProps } from '../../types'; const GraphPropertiesTable = ({ propertiesWithTypes }: GraphPropertiesTableProps): JSX.Element => { - console.log('props', propertiesWithTypes); return (
    diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx index 05facb141..420fbe590 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx @@ -106,7 +106,7 @@ export default function DeduplicationTab() { }); }; - const handleDuplicateNodeClick = async (elementId: string, viewMode: string) => { + const handleDuplicateNodeClick = (elementId: string, viewMode: string) => { handleGraphNodeClick( userCredentials as UserCredentials, elementId, diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/EnitityExtraction/EntityExtractionSetting.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/EnitityExtraction/EntityExtractionSetting.tsx index e5e0bc033..83081dd93 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/EnitityExtraction/EntityExtractionSetting.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/EnitityExtraction/EntityExtractionSetting.tsx @@ -317,8 +317,9 @@ export default function EntityExtractionSetting({ options: nodeLabelOptions, onChange: onChangenodes, value: selectedNodes, - classNamePrefix: `${isTablet ? 'tablet_entity_extraction_Tab_node_label' : 'entity_extraction_Tab_node_label' - }`, + classNamePrefix: `${ + isTablet ? 'tablet_entity_extraction_Tab_node_label' : 'entity_extraction_Tab_node_label' + }`, }} type='creatable' /> @@ -332,8 +333,9 @@ export default function EntityExtractionSetting({ options: relationshipTypeOptions, onChange: onChangerels, value: selectedRels, - classNamePrefix: `${isTablet ? 'tablet_entity_extraction_Tab_relationship_label' : 'entity_extraction_Tab_relationship_label' - }`, + classNamePrefix: `${ + isTablet ? 'tablet_entity_extraction_Tab_relationship_label' : 'entity_extraction_Tab_relationship_label' + }`, }} type='creatable' /> diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 39f9a041c..c43ee5020 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -471,6 +471,7 @@ export interface chatInfoMessage extends Partial { [key: string]: ResponseMode; } | undefined; + multiModelMetrics: multimodelmetric[]; saveInfoEntitites: (entities: Entity[]) => void; saveNodes: (chatNodes: ExtendedNode[]) => void; saveChatRelationships: (chatRels: ExtendedRelationship[]) => void; @@ -479,6 +480,7 @@ export interface chatInfoMessage extends Partial { saveCommunities: (chatCommunities: Community[]) => void; toggleInfoLoading: React.DispatchWithoutAction; toggleMetricsLoading: React.DispatchWithoutAction; + saveMultimodemetrics: (metrics: multimodelmetric[]) => void; } export interface eventResponsetypes extends Omit { @@ -839,7 +841,6 @@ export type GraphPropertiesPanelProps = { newScheme: Scheme; }; - export type withId = { id: string; }; @@ -855,4 +856,3 @@ export interface GraphViewHandlerProps { entityInfo?: Entity[]; mode?: string; } - diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index c67ef5b27..8ab428999 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -125,7 +125,7 @@ export const tooltips = { clearChat: 'Clear Chat History', continue: 'Continue', clearGraphSettings: 'Clear configured Graph Schema', - applySettings:'Apply Graph Schema' + applySettings: 'Apply Graph Schema', }; export const buttonCaptions = { @@ -149,7 +149,7 @@ export const buttonCaptions = { continueSettings: 'Continue', clearSettings: 'Clear Schema', ask: 'Ask', - applyGraphSchema:'Apply' + applyGraphSchema: 'Apply', }; export const POST_PROCESSING_JOBS: { title: string; description: string }[] = [ diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index 5727f33ea..226fd03f9 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -332,7 +332,6 @@ export const filterData = ( filteredNodes = allNodes; filteredRelations = allRelationships; filteredScheme = scheme; - console.log('entity', filteredScheme); } return { filteredNodes, filteredRelations, filteredScheme }; }; From b3f1dd0f78f0b53329e3332762e3989f61254eb7 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Mon, 21 Oct 2024 05:45:36 +0000 Subject: [PATCH 190/292] fix: Multimode metrics mode change state issue fix: chunk list style issue --- frontend/src/components/ChatBot/ChatInfoModal.tsx | 5 +++-- frontend/src/components/ChatBot/ChunkInfo.tsx | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index a8e612ca5..757503fb1 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -78,6 +78,7 @@ const ChatInfoModal: React.FC = ({ const [, copy] = useCopyToClipboard(); const [copiedText, setcopiedText] = useState(false); const [showMetricsTable, setShowMetricsTable] = useState(Boolean(metricDetails)); + const [showMultiModeMetrics, setShowMultiModeMetrics] = useState(Boolean(multiModelMetrics.length)) const [multiModeError, setMultiModeError] = useState(''); const actions: CypherCodeBlockProps['actions'] = useMemo( @@ -200,7 +201,7 @@ const ChatInfoModal: React.FC = ({ } } } else { - setShowMetricsTable(true); + setShowMultiModeMetrics(true) toggleMetricsLoading(); const contextarray = Object.values(activeChatmodes).map((r) => { return r.metric_contexts; @@ -334,7 +335,7 @@ const ChatInfoModal: React.FC = ({ - {showMetricsTable && activeChatmodes != null && Object.keys(activeChatmodes).length > 1 && ( + {showMultiModeMetrics && activeChatmodes != null && Object.keys(activeChatmodes).length > 1 && ( = ({ loading, chunks, mode }) => { ) : chunks?.length > 0 ? (
    -
      +
        {chunks.map((chunk) => (
      • {chunk?.page_number ? ( From fb5e000ef36e36531418a0f82c15199a9666fc2c Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Mon, 21 Oct 2024 05:54:25 +0000 Subject: [PATCH 191/292] fix: list style fix --- frontend/src/components/ChatBot/CommunitiesInfo.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/ChatBot/CommunitiesInfo.tsx b/frontend/src/components/ChatBot/CommunitiesInfo.tsx index f562a4ed4..1a769a1f3 100644 --- a/frontend/src/components/ChatBot/CommunitiesInfo.tsx +++ b/frontend/src/components/ChatBot/CommunitiesInfo.tsx @@ -36,7 +36,7 @@ const CommunitiesInfo: FC = ({ loading, communities, mode }) = ) : communities?.length > 0 ? (
        -
          +
            {communities.map((community, index) => (
          • From fd224a1478e5f98760d6a84ff0e8c9c2bcda93e6 Mon Sep 17 00:00:00 2001 From: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Date: Mon, 21 Oct 2024 11:48:13 +0000 Subject: [PATCH 192/292] Correct TYPO mistake --- backend/score.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/score.py b/backend/score.py index d78a13746..46c4ba137 100644 --- a/backend/score.py +++ b/backend/score.py @@ -291,10 +291,10 @@ async def post_processing(uri=Form(), userName=Form(), password=Form(), database if "enable_communities" in tasks: await asyncio.to_thread(create_communities, uri, userName, password, database) - josn_obj = {'api_name': 'post_processing/create_communities', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} + json_obj = {'api_name': 'post_processing/create_communities', 'db_url': uri, 'logging_time': formatted_time(datetime.now(timezone.utc))} logging.info(f'created communities') - logger.log_struct(josn_obj) + logger.log_struct(json_obj) return create_api_response('Success', message='All tasks completed successfully') except Exception as e: From cb77c187c6274f0b6ec0740ed7ada39fc025ae30 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Mon, 21 Oct 2024 11:49:09 +0000 Subject: [PATCH 193/292] added new env for ragas embedding model --- backend/src/ragas_eval.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/ragas_eval.py b/backend/src/ragas_eval.py index a5ce06b5b..8052cb9a2 100644 --- a/backend/src/ragas_eval.py +++ b/backend/src/ragas_eval.py @@ -9,7 +9,7 @@ from src.shared.common_fn import load_embedding_model load_dotenv() -EMBEDDING_MODEL = os.getenv("EMBEDDING_MODEL") +EMBEDDING_MODEL = os.getenv("RAGAS_EMBEDDING_MODEL") EMBEDDING_FUNCTION, _ = load_embedding_model(EMBEDDING_MODEL) def get_ragas_metrics(question: str, context: list, answer: list, model: str): From 5c0081e28049376d99cba0a7ae24541963c0c322 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Tue, 22 Oct 2024 13:45:47 +0530 Subject: [PATCH 194/292] Props name changes (#811) * Props name changes * removed the accesstoken from row on copy action * props changes for dropzone component * graph view changes --------- Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> --- frontend/src/components/ChatBot/ChunkInfo.tsx | 172 +++++++++--------- frontend/src/components/Content.tsx | 10 +- .../components/DataSources/AWS/S3Modal.tsx | 14 +- .../components/DataSources/GCS/GCSModal.tsx | 18 +- .../components/DataSources/Local/DropZone.tsx | 16 +- .../Local/DropZoneForSmallLayouts.tsx | 16 +- frontend/src/components/FileTable.tsx | 32 ++-- .../EntityExtractionSetting.tsx | 26 ++- .../Popups/GraphEnhancementDialog/index.tsx | 2 +- frontend/src/hooks/useSourceInput.tsx | 14 +- frontend/src/types.ts | 24 +-- 11 files changed, 175 insertions(+), 169 deletions(-) diff --git a/frontend/src/components/ChatBot/ChunkInfo.tsx b/frontend/src/components/ChatBot/ChunkInfo.tsx index 0ebe12f97..b008a30cf 100644 --- a/frontend/src/components/ChatBot/ChunkInfo.tsx +++ b/frontend/src/components/ChatBot/ChunkInfo.tsx @@ -1,7 +1,7 @@ import { FC, useContext, useState } from 'react'; import { ChunkProps, UserCredentials } from '../../types'; import { Box, LoadingSpinner, TextLink, Typography } from '@neo4j-ndl/react'; -import { DocumentTextIconOutline, GlobeAltIconOutline, MagnifyingGlassCircleIconSolid } from '@neo4j-ndl/react/icons'; +import { DocumentTextIconOutline, GlobeAltIconOutline } from '@neo4j-ndl/react/icons'; import wikipedialogo from '../../assets/images/wikipedia.svg'; import youtubelogo from '../../assets/images/youtube.svg'; import gcslogo from '../../assets/images/gcs.webp'; @@ -13,7 +13,6 @@ import { chatModeLables } from '../../utils/Constants'; import { useCredentials } from '../../context/UserCredentials'; import GraphViewModal from '../Graph/GraphViewModal'; import { handleGraphNodeClick } from './chatInfo'; -import { IconButtonWithToolTip } from '../UI/IconButtonToolTip'; const ChunkInfo: FC = ({ loading, chunks, mode }) => { const themeUtils = useContext(ThemeWrapperContext); @@ -24,7 +23,7 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { const [viewPoint, setViewPoint] = useState(''); const [_, setLoadingGraphView] = useState(false); - const handleChunkClick = (elementId: string, viewMode: string) => { + const handleChunkClick = (elementId: string, viewMode: string) => { handleGraphNodeClick( userCredentials as UserCredentials, elementId, @@ -52,16 +51,6 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { <>
            <> - handleChunkClick(chunk.element_id, 'Chunk')} - > - - = ({ loading, chunks, mode }) => {
            Page: {chunk?.page_number}
            +
            + handleChunkClick(chunk.element_id, 'Chunk')} + >{'Graph'} + +
            ) : chunk?.url && chunk?.start_time ? ( <>
            - handleChunkClick(chunk.element_id, 'Chunk')} - > - - = ({ loading, chunks, mode }) => { {mode !== chatModeLables.global_vector && mode !== chatModeLables.entity_vector && mode !== chatModeLables.graph && ( - Similarity Score: {chunk?.score} + <> + Similarity Score: {chunk?.score} +
            + handleChunkClick(chunk.element_id, 'Chunk')} + >{'Graph'} + +
            + )} ) : chunk?.url && new URL(chunk.url).host === 'wikipedia.org' ? ( <>
            - handleChunkClick(chunk.element_id, 'Chunk')} - > - - {chunk?.fileName}
            {mode !== chatModeLables.global_vector && mode !== chatModeLables.entity_vector && mode !== chatModeLables.graph && ( - Similarity Score: {chunk?.score} + <> + Similarity Score: {chunk?.score} +
            + handleChunkClick(chunk.element_id, 'Chunk')} + >{'Graph'} + +
            + )} ) : chunk?.url && new URL(chunk.url).host === 'storage.googleapis.com' ? ( <>
            - handleChunkClick(chunk.element_id, 'Chunk')} - > - - {chunk?.fileName}
            {mode !== chatModeLables.global_vector && mode !== chatModeLables.entity_vector && mode !== chatModeLables.graph && ( - Similarity Score: {chunk?.score} + <> + Similarity Score: {chunk?.score} +
            + handleChunkClick(chunk.element_id, 'Chunk')} + >{'Graph'} + +
            + )} ) : chunk?.url && chunk?.url.startsWith('s3://') ? ( <>
            - handleChunkClick(chunk.element_id, 'Chunk')} - > - - {chunk?.fileName}
            {mode !== chatModeLables.global_vector && mode !== chatModeLables.entity_vector && mode !== chatModeLables.graph && ( - Similarity Score: {chunk?.score} + <> + Similarity Score: {chunk?.score} +
            + handleChunkClick(chunk.element_id, 'Chunk')} + >{'Graph'} + +
            + )} ) : chunk?.url && @@ -181,16 +183,6 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { !isAllowedHost(chunk?.url, ['storage.googleapis.com', 'wikipedia.org', 'youtube.com']) ? ( <>
            - handleChunkClick(chunk.element_id, 'Chunk')} - > - - {chunk?.url} @@ -199,22 +191,23 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { {mode !== chatModeLables.global_vector && mode !== chatModeLables.entity_vector && mode !== chatModeLables.graph && ( - Similarity Score: {chunk?.score} + <> + Similarity Score: {chunk?.score} +
            + handleChunkClick(chunk.element_id, 'Chunk')} + >{'Graph'} + +
            + )} ) : ( <>
            - handleChunkClick(chunk.element_id, 'Chunk')} - > - - {chunk.fileSource === 'local file' ? ( ) : ( @@ -225,12 +218,23 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { className='mr-2' /> )} - - {chunk.fileName} - + <> + + {chunk.fileName} + +
            + handleChunkClick(chunk.element_id, 'Chunk')} + >{'Graph'} + +
            +
            )} diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 3eeace857..eae9caa77 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -308,7 +308,7 @@ const Content: React.FC = ({ userCredentials as UserCredentials, fileItem.fileSource, fileItem.retryOption ?? '', - fileItem.source_url, + fileItem.sourceUrl, localStorage.getItem('accesskey'), localStorage.getItem('secretkey'), fileItem.name ?? '', @@ -316,9 +316,9 @@ const Content: React.FC = ({ fileItem.gcsBucketFolder ?? '', selectedNodes.map((l) => l.value), selectedRels.map((t) => t.value), - fileItem.google_project_id, + fileItem.googleProjectId, fileItem.language, - fileItem.access_token + fileItem.accessToken ); if (apiResponse?.status === 'Failed') { @@ -571,8 +571,8 @@ const Content: React.FC = ({ ...f, status: 'Reprocess', processingProgress: isStartFromBegining ? 0 : f.processingProgress, - NodesCount: isStartFromBegining ? 0 : f.NodesCount, - relationshipCount: isStartFromBegining ? 0 : f.relationshipCount, + NodesCount: isStartFromBegining ? 0 : f.nodesCount, + relationshipCount: isStartFromBegining ? 0 : f.relationshipsCount, } : f; }); diff --git a/frontend/src/components/DataSources/AWS/S3Modal.tsx b/frontend/src/components/DataSources/AWS/S3Modal.tsx index 221fb0c9c..69ac6e7bd 100644 --- a/frontend/src/components/DataSources/AWS/S3Modal.tsx +++ b/frontend/src/components/DataSources/AWS/S3Modal.tsx @@ -30,10 +30,10 @@ const S3Modal: React.FC = ({ hideModal, open }) => { const submitHandler = async (url: string) => { const defaultValues: CustomFileBase = { - processing: 0, + processingTotalTime: 0, status: 'New', - NodesCount: 0, - relationshipCount: 0, + nodesCount: 0, + relationshipsCount: 0, type: 'PDF', model: model, fileSource: 's3 bucket', @@ -81,7 +81,7 @@ const S3Modal: React.FC = ({ hideModal, open }) => { copiedFilesData.unshift({ name: item.fileName, size: item.fileSize, - source_url: item.url, + sourceUrl: item.url, // total_pages: 'N/A', id: uuidv4(), ...defaultValues, @@ -92,9 +92,9 @@ const S3Modal: React.FC = ({ hideModal, open }) => { copiedFilesData.unshift({ ...tempFileData, status: defaultValues.status, - NodesCount: defaultValues.NodesCount, - relationshipCount: defaultValues.relationshipCount, - processing: defaultValues.processing, + nodesCount: defaultValues.nodesCount, + relationshipsCount: defaultValues.relationshipsCount, + processingTotalTime: defaultValues.processingTotalTime, model: defaultValues.model, fileSource: defaultValues.fileSource, processingProgress: defaultValues.processingProgress, diff --git a/frontend/src/components/DataSources/GCS/GCSModal.tsx b/frontend/src/components/DataSources/GCS/GCSModal.tsx index 007ffab2b..039934535 100644 --- a/frontend/src/components/DataSources/GCS/GCSModal.tsx +++ b/frontend/src/components/DataSources/GCS/GCSModal.tsx @@ -23,10 +23,10 @@ const GCSModal: React.FC = ({ hideModal, open, openGCSModal }) => const { setFilesData, model, filesData } = useFileContext(); const defaultValues: CustomFileBase = { - processing: 0, + processingTotalTime: 0, status: 'New', - NodesCount: 0, - relationshipCount: 0, + nodesCount: 0, + relationshipsCount: 0, type: 'TEXT', model: model, fileSource: 'gcs bucket', @@ -101,9 +101,9 @@ const GCSModal: React.FC = ({ hideModal, open, openGCSModal }) => size: item.fileSize ?? 0, gcsBucket: item.gcsBucketName, gcsBucketFolder: item.gcsBucketFolder, - google_project_id: item.gcsProjectId, + googleProjectId: item.gcsProjectId, id: uuidv4(), - access_token: codeResponse.access_token, + accessToken: codeResponse.access_token, ...defaultValues, }); } else { @@ -112,13 +112,13 @@ const GCSModal: React.FC = ({ hideModal, open, openGCSModal }) => copiedFilesData.unshift({ ...tempFileData, status: defaultValues.status, - NodesCount: defaultValues.NodesCount, - relationshipCount: defaultValues.relationshipCount, - processing: defaultValues.processing, + nodesCount: defaultValues.nodesCount, + relationshipsCount: defaultValues.relationshipsCount, + processingTotalTime: defaultValues.processingTotalTime, model: defaultValues.model, fileSource: defaultValues.fileSource, processingProgress: defaultValues.processingProgress, - access_token: codeResponse.access_token, + accessToken: codeResponse.access_token, }); } } diff --git a/frontend/src/components/DataSources/Local/DropZone.tsx b/frontend/src/components/DataSources/Local/DropZone.tsx index 0278e679e..bddbb65f0 100644 --- a/frontend/src/components/DataSources/Local/DropZone.tsx +++ b/frontend/src/components/DataSources/Local/DropZone.tsx @@ -24,13 +24,13 @@ const DropZone: FunctionComponent = () => { setIsLoading(false); if (f.length) { const defaultValues: CustomFileBase = { - processing: 0, + processingTotalTime: 0, status: 'None', - NodesCount: 0, - relationshipCount: 0, + nodesCount: 0, + relationshipsCount: 0, model: model, fileSource: 'local file', - uploadprogess: 0, + uploadProgress: 0, processingProgress: undefined, retryOptionStatus: false, retryOption: '', @@ -46,7 +46,7 @@ const DropZone: FunctionComponent = () => { // @ts-ignore type: `${file.name.substring(file.name.lastIndexOf('.') + 1, file.name.length).toUpperCase()}`, size: file.size, - uploadprogess: file.size && file?.size < chunkSize ? 100 : 0, + uploadProgress: file.size && file?.size < chunkSize ? 100 : 0, id: uuidv4(), ...defaultValues, }); @@ -56,9 +56,9 @@ const DropZone: FunctionComponent = () => { copiedFilesData.unshift({ ...tempFileData, status: defaultValues.status, - NodesCount: defaultValues.NodesCount, - relationshipCount: defaultValues.relationshipCount, - processing: defaultValues.processing, + nodesCount: defaultValues.nodesCount, + relationshipsCount: defaultValues.relationshipsCount, + processingTotalTime: defaultValues.processingTotalTime, model: defaultValues.model, fileSource: defaultValues.fileSource, processingProgress: defaultValues.processingProgress, diff --git a/frontend/src/components/DataSources/Local/DropZoneForSmallLayouts.tsx b/frontend/src/components/DataSources/Local/DropZoneForSmallLayouts.tsx index 17c97d0bc..d7fb1e56d 100644 --- a/frontend/src/components/DataSources/Local/DropZoneForSmallLayouts.tsx +++ b/frontend/src/components/DataSources/Local/DropZoneForSmallLayouts.tsx @@ -170,13 +170,13 @@ export default function DropZoneForSmallLayouts() { setIsLoading(false); if (f.length) { const defaultValues: CustomFileBase = { - processing: 0, + processingTotalTime: 0, status: 'None', - NodesCount: 0, - relationshipCount: 0, + nodesCount: 0, + relationshipsCount: 0, model: model, fileSource: 'local file', - uploadprogess: 0, + uploadProgress: 0, processingProgress: undefined, retryOption: '', retryOptionStatus: false, @@ -192,7 +192,7 @@ export default function DropZoneForSmallLayouts() { // @ts-ignore type: `${file.name.substring(file.name.lastIndexOf('.') + 1, file.name.length).toUpperCase()}`, size: file.size, - uploadprogess: file.size && file?.size < chunkSize ? 100 : 0, + uploadProgress: file.size && file?.size < chunkSize ? 100 : 0, id: uuidv4(), ...defaultValues, }); @@ -202,9 +202,9 @@ export default function DropZoneForSmallLayouts() { copiedFilesData.unshift({ ...tempFileData, status: defaultValues.status, - NodesCount: defaultValues.NodesCount, - relationshipCount: defaultValues.relationshipCount, - processing: defaultValues.processing, + nodesCount: defaultValues.nodesCount, + relationshipsCount: defaultValues.relationshipsCount, + processingTotalTime: defaultValues.processingTotalTime, model: defaultValues.model, fileSource: defaultValues.fileSource, processingProgress: defaultValues.processingProgress, diff --git a/frontend/src/components/FileTable.tsx b/frontend/src/components/FileTable.tsx index 6289c1adf..2032afd28 100644 --- a/frontend/src/components/FileTable.tsx +++ b/frontend/src/components/FileTable.tsx @@ -141,8 +141,8 @@ const FileTable = forwardRef((props, ref) => {
            @@ -307,7 +307,7 @@ const FileTable = forwardRef((props, ref) => { }, }, }), - columnHelper.accessor((row) => row.uploadprogess, { + columnHelper.accessor((row) => row.uploadProgress, { id: 'uploadprogess', cell: (info: CellContext) => { if (parseInt(info.getValue()) === 100 || info.row.original?.status === 'New') { @@ -354,7 +354,7 @@ const FileTable = forwardRef((props, ref) => { return ( - + {info.row.original.fileSource} @@ -487,13 +487,13 @@ const FileTable = forwardRef((props, ref) => { }, }, }), - columnHelper.accessor((row) => row.NodesCount, { + columnHelper.accessor((row) => row.nodesCount, { id: 'NodesCount', cell: (info) => {info.getValue()}, header: () => Nodes, footer: (info) => info.column.id, }), - columnHelper.accessor((row) => row.relationshipCount, { + columnHelper.accessor((row) => row.relationshipsCount, { id: 'relationshipCount', cell: (info) => {info.getValue()}, header: () => Relations, @@ -521,7 +521,11 @@ const FileTable = forwardRef((props, ref) => { label='Copy Row' disabled={info.getValue() === 'Uploading'} clean - onClick={() => handleCopy(info.row.original)} + onClick={() => { + const copied={...info.row.original}; + delete copied.accessToken; + handleCopy(copied); + }} > @@ -661,19 +665,19 @@ const FileTable = forwardRef((props, ref) => { type: item?.fileType?.includes('.') ? item?.fileType?.substring(1)?.toUpperCase() ?? 'None' : item?.fileType?.toUpperCase() ?? 'None', - NodesCount: item?.nodeCount ?? 0, - processing: item?.processingTime ?? 'None', - relationshipCount: item?.relationshipCount ?? 0, + nodesCount: item?.nodeCount ?? 0, + processingTotalTime: item?.processingTime ?? 'None', + relationshipsCount: item?.relationshipCount ?? 0, status: waitingFile ? 'Waiting' : getFileSourceStatus(item), model: item?.model ?? model, id: !waitingFile ? uuidv4() : waitingFile.id, - source_url: item?.url != 'None' && item?.url != '' ? item.url : '', + sourceUrl: item?.url != 'None' && item?.url != '' ? item.url : '', fileSource: item?.fileSource ?? 'None', gcsBucket: item?.gcsBucket, gcsBucketFolder: item?.gcsBucketFolder, errorMessage: item?.errorMessage, - uploadprogess: item?.uploadprogress ?? 0, - google_project_id: item?.gcsProjectId, + uploadProgress: item?.uploadprogress ?? 0, + googleProjectId: item?.gcsProjectId, language: item?.language ?? '', processingProgress: item?.processed_chunk != undefined && @@ -681,7 +685,7 @@ const FileTable = forwardRef((props, ref) => { !isNaN(Math.floor((item?.processed_chunk / item?.total_chunks) * 100)) ? Math.floor((item?.processed_chunk / item?.total_chunks) * 100) : undefined, - access_token: item?.access_token ?? '', + accessToken: item?.accessToken ?? '', retryOption: item.retry_condition ?? '', retryOptionStatus: false, }); diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/EnitityExtraction/EntityExtractionSetting.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/EnitityExtraction/EntityExtractionSetting.tsx index 83081dd93..67dd10f9e 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/EnitityExtraction/EntityExtractionSetting.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/EnitityExtraction/EntityExtractionSetting.tsx @@ -18,7 +18,7 @@ export default function EntityExtractionSetting({ openTextSchema, settingView, onContinue, - colseEnhanceGraphSchemaDialog, + closeEnhanceGraphSchemaDialog, }: { view: 'Dialog' | 'Tabs'; open?: boolean; @@ -26,7 +26,7 @@ export default function EntityExtractionSetting({ openTextSchema: () => void; settingView: 'contentView' | 'headerView'; onContinue?: () => void; - colseEnhanceGraphSchemaDialog?: () => void; + closeEnhanceGraphSchemaDialog?: () => void; }) { const { breakpoints } = tokens; const { @@ -240,16 +240,16 @@ export default function EntityExtractionSetting({ ); localStorage.setItem('selectedSchemas', JSON.stringify({ db: userCredentials?.uri, selectedOptions: [] })); showNormalToast(`Successfully Removed the Schema settings`); - if (view === 'Dialog' && onClose != undefined) { - onClose(); + if (view === 'Tabs' && closeEnhanceGraphSchemaDialog != undefined) { + closeEnhanceGraphSchemaDialog(); } }; const handleApply = () => { setIsSchema(true); localStorage.setItem('isSchema', JSON.stringify(true)); showNormalToast(`Successfully Applied the Schema settings`); - if (view === 'Dialog' && onClose != undefined) { - onClose(); + if (view === 'Tabs' && closeEnhanceGraphSchemaDialog != undefined) { + closeEnhanceGraphSchemaDialog(); } localStorage.setItem( 'selectedNodeLabels', @@ -317,9 +317,8 @@ export default function EntityExtractionSetting({ options: nodeLabelOptions, onChange: onChangenodes, value: selectedNodes, - classNamePrefix: `${ - isTablet ? 'tablet_entity_extraction_Tab_node_label' : 'entity_extraction_Tab_node_label' - }`, + classNamePrefix: `${isTablet ? 'tablet_entity_extraction_Tab_node_label' : 'entity_extraction_Tab_node_label' + }`, }} type='creatable' /> @@ -333,9 +332,8 @@ export default function EntityExtractionSetting({ options: relationshipTypeOptions, onChange: onChangerels, value: selectedRels, - classNamePrefix: `${ - isTablet ? 'tablet_entity_extraction_Tab_relationship_label' : 'entity_extraction_Tab_relationship_label' - }`, + classNamePrefix: `${isTablet ? 'tablet_entity_extraction_Tab_relationship_label' : 'entity_extraction_Tab_relationship_label' + }`, }} type='creatable' /> @@ -363,8 +361,8 @@ export default function EntityExtractionSetting({ if (view === 'Dialog' && onClose != undefined) { onClose(); } - if (view === 'Tabs' && colseEnhanceGraphSchemaDialog != undefined) { - colseEnhanceGraphSchemaDialog(); + if (view === 'Tabs' && closeEnhanceGraphSchemaDialog != undefined) { + closeEnhanceGraphSchemaDialog(); } openTextSchema(); }} diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/index.tsx index c4d9ee2f7..c7b621748 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/index.tsx @@ -102,7 +102,7 @@ export default function GraphEnhancementDialog({ openTextSchema={() => { setShowTextFromSchemaDialog({ triggeredFrom: 'enhancementtab', show: true }); }} - colseEnhanceGraphSchemaDialog={onClose} + closeEnhanceGraphSchemaDialog={onClose} settingView='headerView' />
            diff --git a/frontend/src/hooks/useSourceInput.tsx b/frontend/src/hooks/useSourceInput.tsx index eae33e3d4..7a8b8e7b1 100644 --- a/frontend/src/hooks/useSourceInput.tsx +++ b/frontend/src/hooks/useSourceInput.tsx @@ -47,10 +47,10 @@ export default function useSourceInput( const submitHandler = useCallback( async (url: string) => { const defaultValues: CustomFileBase = { - processing: 0, + processingTotalTime: 0, status: 'New', - NodesCount: 0, - relationshipCount: 0, + nodesCount: 0, + relationshipsCount: 0, type: 'TEXT', model: model, fileSource: fileSource, @@ -122,7 +122,7 @@ export default function useSourceInput( ...defaultValues, }; if (isWikiQuery) { - baseValues.wiki_query = item.fileName; + baseValues.wikiQuery = item.fileName; } copiedFilesData.unshift(baseValues); } else { @@ -131,9 +131,9 @@ export default function useSourceInput( copiedFilesData.unshift({ ...tempFileData, status: defaultValues.status, - NodesCount: defaultValues.NodesCount, - relationshipCount: defaultValues.relationshipCount, - processing: defaultValues.processing, + nodesCount: defaultValues.nodesCount, + relationshipsCount: defaultValues.relationshipsCount, + processingTotalTime: defaultValues.processingTotalTime, model: defaultValues.model, fileSource: defaultValues.fileSource, processingProgress: defaultValues.processingProgress, diff --git a/frontend/src/types.ts b/frontend/src/types.ts index c43ee5020..02dbc0a2b 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -8,24 +8,24 @@ import { BannerType } from '@neo4j-ndl/react'; import Queue from './utils/Queue'; export interface CustomFileBase extends Partial { - processing: number | string; + processingTotalTime: number | string; status: string; - NodesCount: number; - relationshipCount: number; + nodesCount: number; + relationshipsCount: number; model: string; fileSource: string; - source_url?: string; - wiki_query?: string; + sourceUrl?: string; + wikiQuery?: string; gcsBucket?: string; gcsBucketFolder?: string; errorMessage?: string; - uploadprogess?: number; + uploadProgress?: number; processingStatus?: boolean; - google_project_id?: string; + googleProjectId?: string; language?: string; processingProgress?: number; - access_token?: string; - checked?: boolean; + accessToken?: string; + isChecked?: boolean; retryOptionStatus: boolean; retryOption: string; } @@ -45,12 +45,12 @@ export type UserCredentials = { database: string; } & { [key: string]: any }; -export interface SourceNode extends Omit { +export interface SourceNode extends Omit { fileName: string; fileSize: number; fileType: string; nodeCount?: number; - processingTime?: string; + processingTime: string; relationshipCount?: number; url?: string; awsAccessKeyId?: string; @@ -61,7 +61,7 @@ export interface SourceNode extends Omit { retry_condition?: string; } -export type ExtractParams = Pick & { +export type ExtractParams = Pick & { file?: File; aws_access_key_id?: string | null; aws_secret_access_key?: string | null; From ee710028704a50e4fa73ba517da412a6b12b69d9 Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Tue, 22 Oct 2024 08:40:05 +0000 Subject: [PATCH 195/292] test --- frontend/src/components/ChatBot/ChunkInfo.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/frontend/src/components/ChatBot/ChunkInfo.tsx b/frontend/src/components/ChatBot/ChunkInfo.tsx index b008a30cf..68196fb3a 100644 --- a/frontend/src/components/ChatBot/ChunkInfo.tsx +++ b/frontend/src/components/ChatBot/ChunkInfo.tsx @@ -21,7 +21,7 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { const [neoRels, setNeoRels] = useState([]); const [openGraphView, setOpenGraphView] = useState(false); const [viewPoint, setViewPoint] = useState(''); - const [_, setLoadingGraphView] = useState(false); + const [loadingGraphView, setLoadingGraphView] = useState(false); const handleChunkClick = (elementId: string, viewMode: string) => { handleGraphNodeClick( @@ -73,7 +73,7 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { handleChunkClick(chunk.element_id, 'Chunk')} >{'Graph'} @@ -100,7 +100,7 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => {
            handleChunkClick(chunk.element_id, 'Chunk')} >{'Graph'} @@ -123,7 +123,7 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => {
            handleChunkClick(chunk.element_id, 'Chunk')} >{'Graph'} @@ -146,7 +146,7 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => {
            handleChunkClick(chunk.element_id, 'Chunk')} >{'Graph'} @@ -169,7 +169,7 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => {
            handleChunkClick(chunk.element_id, 'Chunk')} >{'Graph'} @@ -196,7 +196,7 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => {
            handleChunkClick(chunk.element_id, 'Chunk')} >{'Graph'} @@ -228,7 +228,7 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => {
            handleChunkClick(chunk.element_id, 'Chunk')} >{'Graph'} From c115014cb53099d6130595fdeebcc836a49f9a74 Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Tue, 22 Oct 2024 09:21:56 +0000 Subject: [PATCH 196/292] view graph --- frontend/src/components/ChatBot/ChunkInfo.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/ChatBot/ChunkInfo.tsx b/frontend/src/components/ChatBot/ChunkInfo.tsx index 68196fb3a..8db4aaa3e 100644 --- a/frontend/src/components/ChatBot/ChunkInfo.tsx +++ b/frontend/src/components/ChatBot/ChunkInfo.tsx @@ -75,7 +75,7 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { label='Graph view' className={`${loadingGraphView ? 'cursor-wait' : 'cursor-pointer'}`} onClick={() => handleChunkClick(chunk.element_id, 'Chunk')} - >{'Graph'} + >{'View Graph'}
            @@ -103,7 +103,7 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { className={`${loadingGraphView ? 'cursor-wait' : 'cursor-pointer'}`} label='Graph view' onClick={() => handleChunkClick(chunk.element_id, 'Chunk')} - >{'Graph'} + >{'View Graph'}
            @@ -126,7 +126,7 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { className={`${loadingGraphView ? 'cursor-wait' : 'cursor-pointer'}`} label='Graph view' onClick={() => handleChunkClick(chunk.element_id, 'Chunk')} - >{'Graph'} + >{'View Graph'}
            @@ -149,7 +149,7 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { className={`${loadingGraphView ? 'cursor-wait' : 'cursor-pointer'}`} label='Graph view' onClick={() => handleChunkClick(chunk.element_id, 'Chunk')} - >{'Graph'} + >{'View Graph'}
            @@ -172,7 +172,7 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { className={`${loadingGraphView ? 'cursor-wait' : 'cursor-pointer'}`} label='Graph view' onClick={() => handleChunkClick(chunk.element_id, 'Chunk')} - >{'Graph'} + >{'View Graph'}
            @@ -199,7 +199,7 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { className={`${loadingGraphView ? 'cursor-wait' : 'cursor-pointer'}`} label='Graph view' onClick={() => handleChunkClick(chunk.element_id, 'Chunk')} - >{'Graph'} + >{'View Graph'}
            @@ -231,7 +231,7 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { className={`${loadingGraphView ? 'cursor-wait' : 'cursor-pointer'}`} label='Graph view' onClick={() => handleChunkClick(chunk.element_id, 'Chunk')} - >{'Graph'} + >{'View Graph'}
            From c200b6105630c8666b9df8081826783467498f27 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Tue, 22 Oct 2024 09:43:13 +0000 Subject: [PATCH 197/292] nodes count and relationshipcount updation fix --- frontend/src/components/DataSources/AWS/S3Modal.tsx | 2 ++ frontend/src/components/DataSources/GCS/GCSModal.tsx | 2 ++ frontend/src/hooks/useSourceInput.tsx | 2 ++ frontend/src/hooks/useSse.tsx | 12 ++++++------ 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/DataSources/AWS/S3Modal.tsx b/frontend/src/components/DataSources/AWS/S3Modal.tsx index 69ac6e7bd..8e809dfff 100644 --- a/frontend/src/components/DataSources/AWS/S3Modal.tsx +++ b/frontend/src/components/DataSources/AWS/S3Modal.tsx @@ -82,6 +82,7 @@ const S3Modal: React.FC = ({ hideModal, open }) => { name: item.fileName, size: item.fileSize, sourceUrl: item.url, + uploadProgress:100, // total_pages: 'N/A', id: uuidv4(), ...defaultValues, @@ -98,6 +99,7 @@ const S3Modal: React.FC = ({ hideModal, open }) => { model: defaultValues.model, fileSource: defaultValues.fileSource, processingProgress: defaultValues.processingProgress, + uploadProgress:100, }); } }); diff --git a/frontend/src/components/DataSources/GCS/GCSModal.tsx b/frontend/src/components/DataSources/GCS/GCSModal.tsx index 039934535..01b405cee 100644 --- a/frontend/src/components/DataSources/GCS/GCSModal.tsx +++ b/frontend/src/components/DataSources/GCS/GCSModal.tsx @@ -105,6 +105,7 @@ const GCSModal: React.FC = ({ hideModal, open, openGCSModal }) => id: uuidv4(), accessToken: codeResponse.access_token, ...defaultValues, + uploadProgress:100 }); } else { const tempFileData = copiedFilesData[filedataIndex]; @@ -119,6 +120,7 @@ const GCSModal: React.FC = ({ hideModal, open, openGCSModal }) => fileSource: defaultValues.fileSource, processingProgress: defaultValues.processingProgress, accessToken: codeResponse.access_token, + uploadProgress:100 }); } } diff --git a/frontend/src/hooks/useSourceInput.tsx b/frontend/src/hooks/useSourceInput.tsx index 7a8b8e7b1..cbdc24b8f 100644 --- a/frontend/src/hooks/useSourceInput.tsx +++ b/frontend/src/hooks/useSourceInput.tsx @@ -118,6 +118,7 @@ export default function useSourceInput( source_url: item.url, id: uuidv4(), language: item.language, + uploadProgress:100, // total_pages: 1, ...defaultValues, }; @@ -137,6 +138,7 @@ export default function useSourceInput( model: defaultValues.model, fileSource: defaultValues.fileSource, processingProgress: defaultValues.processingProgress, + uploadProgress:100, }); } } diff --git a/frontend/src/hooks/useSse.tsx b/frontend/src/hooks/useSse.tsx index dadf4d184..5612dc747 100644 --- a/frontend/src/hooks/useSse.tsx +++ b/frontend/src/hooks/useSse.tsx @@ -38,10 +38,10 @@ export default function useServerSideEvent( return { ...curfile, status: total_chunks === processed_chunk ? 'Completed' : status, - NodesCount: nodeCount, - relationshipCount: relationshipCount, + nodesCount: nodeCount, + relationshipsCount: relationshipCount, model: model, - processing: processingTime?.toFixed(2), + processingTotalTime: processingTime?.toFixed(2), processingProgress: Math.floor((processed_chunk / total_chunks) * 100), }; } @@ -57,10 +57,10 @@ export default function useServerSideEvent( return { ...curfile, status: status, - NodesCount: nodeCount, - relationshipCount: relationshipCount, + nodesCount: nodeCount, + relationshipsCount: relationshipCount, model: model, - processing: processingTime?.toFixed(2), + processingTotalTime: processingTime?.toFixed(2), }; } return curfile; From 340679b6db8599ccae2d50672c433f897fea210f Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Tue, 22 Oct 2024 10:44:35 +0000 Subject: [PATCH 198/292] sourceUrl Fix --- frontend/src/hooks/useSourceInput.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/hooks/useSourceInput.tsx b/frontend/src/hooks/useSourceInput.tsx index cbdc24b8f..ee75a8cb4 100644 --- a/frontend/src/hooks/useSourceInput.tsx +++ b/frontend/src/hooks/useSourceInput.tsx @@ -115,7 +115,7 @@ export default function useSourceInput( const baseValues = { name: item.fileName, size: item.fileSize, - source_url: item.url, + sourceUrl: item.url, id: uuidv4(), language: item.language, uploadProgress:100, From fb35bda20dbeb84847887dd42cb435c6a3ba2009 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Wed, 23 Oct 2024 06:16:26 +0000 Subject: [PATCH 199/292] empty string "" fix to keep the default values we should keep the value blank instead "" --- docker-compose.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 7761704c7..afc87b848 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -52,15 +52,15 @@ services: dockerfile: Dockerfile args: - VITE_BACKEND_API_URL=${VITE_BACKEND_API_URL-http://localhost:8000} - - VITE_REACT_APP_SOURCES=${VITE_REACT_APP_SOURCES-local,youtube,wiki,s3} - - VITE_LLM_MODELS=${VITE_LLM_MODELS-diffbot,openai-gpt-3.5,openai-gpt-4o} - - VITE_GOOGLE_CLIENT_ID=${VITE_GOOGLE_CLIENT_ID-""} + - VITE_REACT_APP_SOURCES=${VITE_REACT_APP_SOURCES-local,wiki,s3} + - VITE_LLM_MODELS=${VITE_LLM_MODELS-} + - VITE_GOOGLE_CLIENT_ID=${VITE_GOOGLE_CLIENT_ID-} - VITE_BLOOM_URL=${VITE_BLOOM_URL-https://workspace-preview.neo4j.io/workspace/explore?connectURL={CONNECT_URL}&search=Show+me+a+graph&featureGenAISuggestions=true&featureGenAISuggestionsInternal=true} - VITE_TIME_PER_PAGE=${VITE_TIME_PER_PAGE-50} - VITE_CHUNK_SIZE=${VITE_CHUNK_SIZE-5242880} - VITE_LARGE_FILE_SIZE=${VITE_LARGE_FILE_SIZE-5242880} - VITE_ENV=${VITE_ENV-DEV} - - VITE_CHAT_MODES=${VITE_CHAT_MODES-""} + - VITE_CHAT_MODES=${VITE_CHAT_MODES-} - VITE_BATCH_SIZE=${VITE_BATCH_SIZE-2} volumes: - ./frontend:/app From ed18462dcbcd8d2678d2dbf0fcfbe3e77af15501 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Wed, 23 Oct 2024 07:07:35 +0000 Subject: [PATCH 200/292] prop changes --- frontend/src/components/Content.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index eae9caa77..4b10f4242 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -331,10 +331,10 @@ const Content: React.FC = ({ const apiRes = apiResponse?.data; return { ...curfile, - processing: apiRes?.processingTime?.toFixed(2), + processingProgress: apiRes?.processingTime?.toFixed(2), status: apiRes?.status, - NodesCount: apiRes?.nodeCount, - relationshipCount: apiRes?.relationshipCount, + nodesCount: apiRes?.nodeCount, + relationshipsCount: apiRes?.relationshipCount, model: apiRes?.model, }; } From 985993e2f6a773b46b2e5760f6778beacbff9bca Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Wed, 23 Oct 2024 07:10:18 +0000 Subject: [PATCH 201/292] props changes --- frontend/src/components/Content.tsx | 2 +- frontend/src/components/FileTable.tsx | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 4b10f4242..cd7ed14ea 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -571,7 +571,7 @@ const Content: React.FC = ({ ...f, status: 'Reprocess', processingProgress: isStartFromBegining ? 0 : f.processingProgress, - NodesCount: isStartFromBegining ? 0 : f.nodesCount, + nodesCount: isStartFromBegining ? 0 : f.nodesCount, relationshipCount: isStartFromBegining ? 0 : f.relationshipsCount, } : f; diff --git a/frontend/src/components/FileTable.tsx b/frontend/src/components/FileTable.tsx index 2032afd28..b3fbafd55 100644 --- a/frontend/src/components/FileTable.tsx +++ b/frontend/src/components/FileTable.tsx @@ -823,10 +823,10 @@ const FileTable = forwardRef((props, ref) => { return { ...curfile, status: status, - NodesCount: nodeCount, + nodesCount: nodeCount, relationshipCount: relationshipCount, model: model, - processing: processingTime?.toFixed(2), + processingTotalTime: processingTime?.toFixed(2), processingProgress: Math.floor((processed_chunk / total_chunks) * 100), }; } @@ -853,7 +853,7 @@ const FileTable = forwardRef((props, ref) => { return { ...curfile, status: status, - NodesCount: nodeCount, + nodesCount: nodeCount, relationshipCount: relationshipCount, processingProgress: Math.floor((processed_chunk / total_chunks) * 100), }; From 220bee77648f8c3e7361eeb88f6355c2cd6d8e5b Mon Sep 17 00:00:00 2001 From: aashipandya <156318202+aashipandya@users.noreply.github.com> Date: Wed, 23 Oct 2024 13:20:59 +0530 Subject: [PATCH 202/292] retry condition update for failed files (#820) --- backend/score.py | 2 +- backend/src/graphDB_dataAccess.py | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/backend/score.py b/backend/score.py index 46c4ba137..48945fb7d 100644 --- a/backend/score.py +++ b/backend/score.py @@ -223,7 +223,7 @@ async def extract_knowledge_graph_from_file( except Exception as e: message=f"Failed To Process File:{file_name} or LLM Unable To Parse Content " error_message = str(e) - graphDb_data_Access.update_exception_db(file_name,error_message) + graphDb_data_Access.update_exception_db(file_name,error_message, retry_condition) gcs_file_cache = os.environ.get('GCS_FILE_CACHE') if source_type == 'local file': if gcs_file_cache == 'True': diff --git a/backend/src/graphDB_dataAccess.py b/backend/src/graphDB_dataAccess.py index e3b923f37..f5d1b228c 100644 --- a/backend/src/graphDB_dataAccess.py +++ b/backend/src/graphDB_dataAccess.py @@ -17,14 +17,19 @@ class graphDBdataAccess: def __init__(self, graph: Neo4jGraph): self.graph = graph - def update_exception_db(self, file_name, exp_msg): + def update_exception_db(self, file_name, exp_msg, retry_condition): try: job_status = "Failed" result = self.get_current_status_document_node(file_name) is_cancelled_status = result[0]['is_cancelled'] if bool(is_cancelled_status) == True: job_status = 'Cancelled' - self.graph.query("""MERGE(d:Document {fileName :$fName}) SET d.status = $status, d.errorMessage = $error_msg""", + if retry_condition is not None: + retry_condition = None + self.graph.query("""MERGE(d:Document {fileName :$fName}) SET d.status = $status, d.errorMessage = $error_msg, d.retry_condition = $retry_condition""", + {"fName":file_name, "status":job_status, "error_msg":exp_msg, "retry_condition":retry_condition}) + else : + self.graph.query("""MERGE(d:Document {fileName :$fName}) SET d.status = $status, d.errorMessage = $error_msg""", {"fName":file_name, "status":job_status, "error_msg":exp_msg}) except Exception as e: error_message = str(e) From 05085858fdefe76572de86cf85cede7192fd7744 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Wed, 23 Oct 2024 15:32:05 +0530 Subject: [PATCH 203/292] Chat modes name changes (#815) * Props name changes * removed the accesstoken from row on copy action * updated chat mode names * Chat Modes Name Changes * lint fixes * using readble format In UI * removal of size to avoid console warning * key add --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> --- backend/src/shared/constants.py | 10 ++--- .../src/components/ChatBot/ChatInfoModal.tsx | 28 +++++++----- .../src/components/ChatBot/ChatModeToggle.tsx | 22 +++++----- .../components/ChatBot/ChatModesSwitch.tsx | 3 +- frontend/src/components/ChatBot/Chatbot.tsx | 4 +- frontend/src/components/ChatBot/ChunkInfo.tsx | 43 ++++++++----------- .../components/ChatBot/CommunitiesInfo.tsx | 2 +- .../src/components/ChatBot/SourcesInfo.tsx | 7 ++- frontend/src/components/Content.tsx | 2 +- .../SelectedJobList.tsx | 13 +++--- frontend/src/context/UsersFiles.tsx | 2 +- frontend/src/utils/Constants.ts | 19 ++++++-- frontend/src/utils/Utils.ts | 10 ++--- 13 files changed, 89 insertions(+), 76 deletions(-) diff --git a/backend/src/shared/constants.py b/backend/src/shared/constants.py index cde354f16..b58fd3a67 100644 --- a/backend/src/shared/constants.py +++ b/backend/src/shared/constants.py @@ -560,12 +560,12 @@ CHAT_VECTOR_MODE = "vector" CHAT_FULLTEXT_MODE = "fulltext" -CHAT_ENTITY_VECTOR_MODE = "entity search+vector" -CHAT_VECTOR_GRAPH_MODE = "graph+vector" -CHAT_VECTOR_GRAPH_FULLTEXT_MODE = "graph+vector+fulltext" -CHAT_GLOBAL_VECTOR_FULLTEXT_MODE = "global search+vector+fulltext" +CHAT_ENTITY_VECTOR_MODE = "entity_vector" +CHAT_VECTOR_GRAPH_MODE = "graph_vector" +CHAT_VECTOR_GRAPH_FULLTEXT_MODE = "graph_vector_fulltext" +CHAT_GLOBAL_VECTOR_FULLTEXT_MODE = "global_vector" CHAT_GRAPH_MODE = "graph" -CHAT_DEFAULT_MODE = "graph+vector+fulltext" +CHAT_DEFAULT_MODE = "graph_vector_fulltext" CHAT_MODE_CONFIG_MAP= { CHAT_VECTOR_MODE : { diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index 757503fb1..4ffdd9acd 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -24,7 +24,7 @@ import ChunkInfo from './ChunkInfo'; import EntitiesInfo from './EntitiesInfo'; import SourcesInfo from './SourcesInfo'; import CommunitiesInfo from './CommunitiesInfo'; -import { chatModeLables, supportedLLmsForRagas } from '../../utils/Constants'; +import { chatModeLables, chatModeReadableLables, supportedLLmsForRagas } from '../../utils/Constants'; import { Relationship } from '@neo4j-nvl/base'; import { getChatMetrics } from '../../services/GetRagasMetric'; import MetricsTab from './MetricsTab'; @@ -71,14 +71,20 @@ const ChatInfoModal: React.FC = ({ const { breakpoints } = tokens; const isTablet = useMediaQuery(`(min-width:${breakpoints.xs}) and (max-width: ${breakpoints.lg})`); const [activeTab, setActiveTab] = useState( - error?.length ? 10 : mode === chatModeLables.global_vector ? 7 : mode === chatModeLables.graph ? 4 : 3 + error?.length + ? 10 + : mode === chatModeLables['global search+vector+fulltext'] + ? 7 + : mode === chatModeLables.graph + ? 4 + : 3 ); const { userCredentials } = useCredentials(); const themeUtils = useContext(ThemeWrapperContext); const [, copy] = useCopyToClipboard(); const [copiedText, setcopiedText] = useState(false); const [showMetricsTable, setShowMetricsTable] = useState(Boolean(metricDetails)); - const [showMultiModeMetrics, setShowMultiModeMetrics] = useState(Boolean(multiModelMetrics.length)) + const [showMultiModeMetrics, setShowMultiModeMetrics] = useState(Boolean(multiModelMetrics.length)); const [multiModeError, setMultiModeError] = useState(''); const actions: CypherCodeBlockProps['actions'] = useMemo( @@ -201,7 +207,7 @@ const ChatInfoModal: React.FC = ({ } } } else { - setShowMultiModeMetrics(true) + setShowMultiModeMetrics(true); toggleMetricsLoading(); const contextarray = Object.values(activeChatmodes).map((r) => { return r.metric_contexts; @@ -255,7 +261,7 @@ const ChatInfoModal: React.FC = ({ To generate this response, the process took {response_time} seconds, utilizing {total_tokens} tokens with the model{' '} {model} in{' '} - {mode !== 'vector' ? mode.replace(/\+/g, ' & ') : mode} mode. + {chatModeReadableLables[mode] !== 'vector' ? chatModeReadableLables[mode].replace(/\+/g, ' & ') : chatModeReadableLables[mode]} mode.
            @@ -263,16 +269,16 @@ const ChatInfoModal: React.FC = ({ {error} ) : ( - {mode === chatModeLables.global_vector ? ( + {mode === chatModeLables['global search+vector+fulltext'] ? ( Communities ) : ( <> {mode != chatModeLables.graph ? Sources used : <>} {mode != chatModeLables.graph ? Chunks : <>} - {mode === chatModeLables.graph_vector || + {mode === chatModeLables['graph+vector'] || mode === chatModeLables.graph || - mode === chatModeLables.graph_vector_fulltext || - mode === chatModeLables.entity_vector ? ( + mode === chatModeLables['graph+vector+fulltext'] || + mode === chatModeLables['entity search+vector'] ? ( Top Entities used ) : ( <> @@ -282,7 +288,7 @@ const ChatInfoModal: React.FC = ({ ) : ( <> )} - {mode === chatModeLables.entity_vector && communities.length ? ( + {mode === chatModeLables['entity search+vector'] && communities.length ? ( Communities ) : ( <> @@ -387,7 +393,7 @@ const ChatInfoModal: React.FC = ({ className='min-h-40' /> - {mode === chatModeLables.entity_vector || mode === chatModeLables.global_vector ? ( + {mode === chatModeLables['entity search+vector'] || mode === chatModeLables['global search+vector+fulltext'] ? ( diff --git a/frontend/src/components/ChatBot/ChatModeToggle.tsx b/frontend/src/components/ChatBot/ChatModeToggle.tsx index a892ca01d..52df01a4a 100644 --- a/frontend/src/components/ChatBot/ChatModeToggle.tsx +++ b/frontend/src/components/ChatBot/ChatModeToggle.tsx @@ -2,7 +2,7 @@ import { StatusIndicator, Typography } from '@neo4j-ndl/react'; import { useMemo, useEffect } from 'react'; import { useFileContext } from '../../context/UsersFiles'; import CustomMenu from '../UI/Menu'; -import { chatModeLables, chatModes as AvailableModes } from '../../utils/Constants'; +import { chatModeLables, chatModes as AvailableModes, chatModeReadableLables } from '../../utils/Constants'; import { capitalize } from '@mui/material'; import { capitalizeWithPlus } from '../../utils/Utils'; import { useCredentials } from '../../context/UserCredentials'; @@ -30,16 +30,16 @@ export default function ChatModeToggle({ if ( chatModes.includes(chatModeLables.graph) || chatModes.includes(chatModeLables.fulltext) || - chatModes.includes(chatModeLables.graph_vector_fulltext) + chatModes.includes(chatModeLables['global search+vector+fulltext']) ) { setchatModes((prev) => prev.filter( - (m) => ![chatModeLables.graph, chatModeLables.fulltext, chatModeLables.graph_vector_fulltext].includes(m) + (m) => ![chatModeLables.graph, chatModeLables.fulltext, chatModeLables['graph+vector+fulltext']].includes(m) ) ); } - if (!chatModes.includes(chatModeLables.vector)) { - setchatModes([chatModeLables.vector]); + if (!(chatModes.includes(chatModeLables.vector) || chatModes.includes(chatModeLables['graph+vector']))) { + setchatModes([chatModeLables['graph+vector']]); } } }, [selectedRows.length, chatModes.length]); @@ -47,16 +47,16 @@ export default function ChatModeToggle({ const memoizedChatModes = useMemo(() => { return isGdsActive && isCommunityAllowed ? AvailableModes - : AvailableModes?.filter((m) => !m.mode.includes(chatModeLables.global_vector)); + : AvailableModes?.filter((m) => !m.mode.includes(chatModeLables['global search+vector+fulltext'])); }, [isGdsActive, isCommunityAllowed]); const menuItems = useMemo(() => { return memoizedChatModes?.map((m) => { const isDisabled = Boolean( - selectedRows.length && !(m.mode === chatModeLables.vector || m.mode === chatModeLables.graph_vector) + selectedRows.length && !(m.mode === chatModeLables.vector || m.mode === chatModeLables['graph+vector']) ); const handleModeChange = () => { if (isDisabled) { - setchatModes([chatModeLables.graph_vector]); + setchatModes([chatModeLables['graph+vector']]); } else if (chatModes.includes(m.mode)) { setchatModes((prev) => prev.filter((i) => i != m.mode)); } else { @@ -68,7 +68,9 @@ export default function ChatModeToggle({ title: (
            - {m.mode.includes('+') ? capitalizeWithPlus(m.mode) : capitalize(m.mode)} + {chatModeReadableLables[m.mode].includes('+') + ? capitalizeWithPlus(chatModeReadableLables[m.mode]) + : capitalize(chatModeReadableLables[m.mode])}
            {m.description} @@ -97,7 +99,7 @@ export default function ChatModeToggle({ useEffect(() => { if (!selectedRows.length && !chatModes.length) { - setchatModes([chatModeLables.graph_vector_fulltext]); + setchatModes([]); } }, [selectedRows.length, chatModes.length]); return ( diff --git a/frontend/src/components/ChatBot/ChatModesSwitch.tsx b/frontend/src/components/ChatBot/ChatModesSwitch.tsx index a958b1a06..db91e3372 100644 --- a/frontend/src/components/ChatBot/ChatModesSwitch.tsx +++ b/frontend/src/components/ChatBot/ChatModesSwitch.tsx @@ -2,6 +2,7 @@ import { Flex, IconButton } from '@neo4j-ndl/react'; import { ChevronLeftIconSolid, ChevronRightIconSolid } from '@neo4j-ndl/react/icons'; import TipWrapper from '../UI/TipWrapper'; import { capitalize, capitalizeWithPlus } from '../../utils/Utils'; +import { chatModeReadableLables } from '../../utils/Constants'; export default function ChatModesSwitch({ switchToOtherMode, @@ -16,7 +17,7 @@ export default function ChatModesSwitch({ currentMode: string; isFullScreen: boolean; }) { - const chatmodetoshow = currentMode.includes('+') ? capitalizeWithPlus(currentMode) : capitalize(currentMode); + const chatmodetoshow =chatModeReadableLables[currentMode].includes('+') ? capitalizeWithPlus(chatModeReadableLables[currentMode]) : capitalize(chatModeReadableLables[currentMode]); return ( = (props) => { const [responseTime, setResponseTime] = useState(0); const [tokensUsed, setTokensUsed] = useState(0); const [cypherQuery, setcypherQuery] = useState(''); - const [chatsMode, setChatsMode] = useState(chatModeLables.graph_vector_fulltext); + const [chatsMode, setChatsMode] = useState(chatModeLables['graph+vector+fulltext']); const [graphEntitites, setgraphEntitites] = useState<[]>([]); const [messageError, setmessageError] = useState(''); const [entitiesModal, setEntitiesModal] = useState([]); @@ -583,7 +583,7 @@ const Chatbot: FC = (props) => { }} onClose={() => setShowInfoModal(false)} open={showInfoModal} - size={activeChat?.currentMode === chatModeLables.entity_vector ? 'large' : 'medium'} + size={activeChat?.currentMode === chatModeLables['entity search+vector'] ? 'large' : 'medium'} >
            = ({ loading, chunks, mode }) => {
            - {mode !== chatModeLables.global_vector && - mode !== chatModeLables.entity_vector && + {mode !== chatModeLables['global search+vector+fulltext'] && + mode !== chatModeLables['entity search+vector'] && mode !== chatModeLables.graph && chunk.score && ( Similarity Score: {chunk?.score} @@ -71,11 +71,10 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => {
            handleChunkClick(chunk.element_id, 'Chunk')} - >{'Graph'} + >{'View Graph'}
            @@ -92,14 +91,13 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => {
            - {mode !== chatModeLables.global_vector && - mode !== chatModeLables.entity_vector && + {mode !== chatModeLables['global search+vector+fulltext'] && + mode !== chatModeLables['entity search+vector'] && mode !== chatModeLables.graph && ( <> Similarity Score: {chunk?.score}
            handleChunkClick(chunk.element_id, 'Chunk')} @@ -115,18 +113,17 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { {chunk?.fileName}
            - {mode !== chatModeLables.global_vector && - mode !== chatModeLables.entity_vector && + {mode !== chatModeLables['global search+vector+fulltext'] && + mode !== chatModeLables['entity search+vector'] && mode !== chatModeLables.graph && ( <> Similarity Score: {chunk?.score}
            handleChunkClick(chunk.element_id, 'Chunk')} - >{'Graph'} + >{'View Graph'}
            @@ -138,18 +135,17 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { {chunk?.fileName}
            - {mode !== chatModeLables.global_vector && - mode !== chatModeLables.entity_vector && + {mode !== chatModeLables['global search+vector+fulltext'] && + mode !== chatModeLables['entity search+vector'] && mode !== chatModeLables.graph && ( <> Similarity Score: {chunk?.score}
            handleChunkClick(chunk.element_id, 'Chunk')} - >{'Graph'} + >{'View Graph'}
            @@ -161,18 +157,17 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { {chunk?.fileName}
            - {mode !== chatModeLables.global_vector && - mode !== chatModeLables.entity_vector && + {mode !== chatModeLables['global search+vector+fulltext'] && + mode !== chatModeLables['entity search+vector'] && mode !== chatModeLables.graph && ( <> Similarity Score: {chunk?.score}
            handleChunkClick(chunk.element_id, 'Chunk')} - >{'Graph'} + >{'View Graph'}
            @@ -188,18 +183,17 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { {chunk?.url}
            - {mode !== chatModeLables.global_vector && - mode !== chatModeLables.entity_vector && + {mode !== chatModeLables['global search+vector+fulltext'] && + mode !== chatModeLables['entity search+vector'] && mode !== chatModeLables.graph && ( <> Similarity Score: {chunk?.score}
            handleChunkClick(chunk.element_id, 'Chunk')} - >{'Graph'} + >{'View Graph'}
            @@ -227,11 +221,10 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => {
            handleChunkClick(chunk.element_id, 'Chunk')} - >{'Graph'} + >{'View Graph'}
            diff --git a/frontend/src/components/ChatBot/CommunitiesInfo.tsx b/frontend/src/components/ChatBot/CommunitiesInfo.tsx index 1a769a1f3..bc8e5e8d3 100644 --- a/frontend/src/components/ChatBot/CommunitiesInfo.tsx +++ b/frontend/src/components/ChatBot/CommunitiesInfo.tsx @@ -47,7 +47,7 @@ const CommunitiesInfo: FC = ({ loading, communities, mode }) = onClick={() => handleCommunityClick(community.element_id, 'chatInfoView')} >{`ID : ${community.id}`} - {mode === chatModeLables.global_vector && community.score && ( + {mode === chatModeLables['global search+vector+fulltext'] && community.score && ( Score : {community.score} diff --git a/frontend/src/components/ChatBot/SourcesInfo.tsx b/frontend/src/components/ChatBot/SourcesInfo.tsx index 35d76aefb..a934913d9 100644 --- a/frontend/src/components/ChatBot/SourcesInfo.tsx +++ b/frontend/src/components/ChatBot/SourcesInfo.tsx @@ -16,10 +16,9 @@ const filterUniqueChunks = (chunks: Chunk[]) => { const sourceCheck = `${chunk.fileName}-${chunk.fileSource}`; if (chunkSource.has(sourceCheck)) { return false; - } - chunkSource.add(sourceCheck); - return true; - + } + chunkSource.add(sourceCheck); + return true; }); }; diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index cd7ed14ea..c5dceaf36 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -552,7 +552,7 @@ const Content: React.FC = ({ setSelectedNodes([]); setSelectedRels([]); setClearHistoryData(true); - setchatModes([chatModeLables.graph_vector_fulltext]); + setchatModes([chatModeLables['graph+vector+fulltext']]); }; const retryHandler = async (filename: string, retryoption: string) => { diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx index 1cb3c7310..348c97af2 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx @@ -11,18 +11,19 @@ export default function SelectedJobList({ }) { const ongoingPostProcessingTasks = useMemo( () => - (isGdsActive - ? postProcessingTasks.includes('enable_communities') - ? postProcessingTasks - : postProcessingTasks.filter((s) => s != 'enable_communities') - : postProcessingTasks.filter((s) => s != 'enable_communities')), + (isGdsActive + ? postProcessingTasks.includes('enable_communities') + ? postProcessingTasks + : postProcessingTasks.filter((s) => s != 'enable_communities') + : postProcessingTasks.filter((s) => s != 'enable_communities')), [isGdsActive, postProcessingTasks] ); return ( - {ongoingPostProcessingTasks.map((task) => { + {ongoingPostProcessingTasks.map((task, idx) => { return ( {task diff --git a/frontend/src/context/UsersFiles.tsx b/frontend/src/context/UsersFiles.tsx index 14f5a0245..935f75f10 100644 --- a/frontend/src/context/UsersFiles.tsx +++ b/frontend/src/context/UsersFiles.tsx @@ -29,7 +29,7 @@ const FileContextProvider: FC = ({ children }) => { const [selectedSchemas, setSelectedSchemas] = useState([]); const [rowSelection, setRowSelection] = useState>({}); const [selectedRows, setSelectedRows] = useState([]); - const [chatModes, setchatModes] = useState([chatModeLables.graph_vector_fulltext]); + const [chatModes, setchatModes] = useState([chatModeLables['graph+vector+fulltext']]); const [isSchema, setIsSchema] = useState(false); const [showTextFromSchemaDialog, setShowTextFromSchemaDialog] = useState({ triggeredFrom: '', diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index 8ab428999..0043dc241 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -47,6 +47,17 @@ export const supportedLLmsForRagas = [ 'bedrock_claude_3_5_sonnet', ]; export const chatModeLables = { + vector: 'vector', + graph: 'graph', + 'graph+vector': 'graph_vector', + fulltext: 'fulltext', + 'graph+vector+fulltext': 'graph_vector_fulltext', + 'entity search+vector': 'entity_vector', + unavailableChatMode: 'Chat mode is unavailable when files are selected', + selected: 'Selected', + 'global search+vector+fulltext': 'global_vector', +}; +export const chatModeReadableLables: Record = { vector: 'vector', graph: 'graph', graph_vector: 'graph+vector', @@ -73,7 +84,7 @@ export const chatModes = description: 'Translates text to Cypher queries for precise data retrieval from a graph database.', }, { - mode: chatModeLables.graph_vector, + mode: chatModeLables['graph+vector'], description: 'Combines vector indexing and graph connections for contextually enhanced semantic search.', }, { @@ -81,15 +92,15 @@ export const chatModes = description: 'Conducts fast, keyword-based search using full-text indexing on text chunks.', }, { - mode: chatModeLables.graph_vector_fulltext, + mode: chatModeLables['graph+vector+fulltext'], description: 'Integrates vector, graph, and full-text indexing for comprehensive search results.', }, { - mode: chatModeLables.entity_vector, + mode: chatModeLables['entity search+vector'], description: 'Uses vector indexing on entity nodes for highly relevant entity-based search.', }, { - mode: chatModeLables.global_vector, + mode: chatModeLables['global search+vector+fulltext'], description: 'Use vector and full-text indexing on community nodes to provide accurate, context-aware answers globally.', }, diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index 226fd03f9..6945c17ca 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -417,15 +417,15 @@ export const getDescriptionForChatMode = (mode: string): string => { return 'Utilizes vector indexing on text chunks to enable semantic similarity search.'; case chatModeLables.graph: return 'Leverages text-to-cypher translation to query a database and retrieve relevant data, ensuring a highly targeted and contextually accurate response.'; - case chatModeLables.graph_vector: + case chatModeLables['graph+vector']: return 'Combines vector indexing on text chunks with graph connections, enhancing search results with contextual relevance by considering relationships between concepts.'; case chatModeLables.fulltext: return 'Employs a fulltext index on text chunks for rapid keyword-based search, efficiently identifying documents containing specific words or phrases.'; - case chatModeLables.graph_vector_fulltext: + case chatModeLables['graph+vector+fulltext']: return 'Merges vector indexing, graph connections, and fulltext indexing for a comprehensive search approach, combining semantic similarity, contextual relevance, and keyword-based search for optimal results.'; - case chatModeLables.entity_vector: + case chatModeLables['entity search+vector']: return 'Combines entity node vector indexing with graph connections for accurate entity-based search, providing the most relevant response.'; - case chatModeLables.global_vector: + case chatModeLables['global search+vector+fulltext']: return 'Use vector and full-text indexing on community nodes to provide accurate, context-aware answers globally.'; default: return 'Chat mode description not available'; // Fallback description @@ -510,7 +510,7 @@ export function downloadClickHandler( } export function getNodes(nodesData: Array, mode: string) { return nodesData.map((n) => { - if (!n.labels.length && mode === chatModeLables.entity_vector) { + if (!n.labels.length && mode === chatModeLables['entity search+vector']) { return { ...n, labels: ['Entity'], From 9dba36139bca079dbf52b1ce1a589b77882c9022 Mon Sep 17 00:00:00 2001 From: aashipandya <156318202+aashipandya@users.noreply.github.com> Date: Wed, 23 Oct 2024 16:59:47 +0530 Subject: [PATCH 204/292] Youtube transcript fix with proxy (#822) --- backend/example.env | 1 + backend/src/document_sources/youtube.py | 25 ++++++++++++++----------- backend/src/main.py | 5 +++-- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/backend/example.env b/backend/example.env index 75b817220..5d366f21c 100644 --- a/backend/example.env +++ b/backend/example.env @@ -40,4 +40,5 @@ LLM_MODEL_CONFIG_anthropic_claude_3_5_sonnet="model_name,anthropic_api_key" LLM_MODEL_CONFIG_fireworks_llama_v3_70b="model_name,fireworks_api_key" LLM_MODEL_CONFIG_bedrock_claude_3_5_sonnet="model_name,aws_access_key_id,aws_secret__access_key,region_name" LLM_MODEL_CONFIG_ollama_llama3="model_name,model_local_url" +YOUTUBE_TRANSCRIPT_PROXY="https://user:pass@domain:port" diff --git a/backend/src/document_sources/youtube.py b/backend/src/document_sources/youtube.py index fce62774d..e30de301e 100644 --- a/backend/src/document_sources/youtube.py +++ b/backend/src/document_sources/youtube.py @@ -17,22 +17,25 @@ def get_youtube_transcript(youtube_id): try: #transcript = YouTubeTranscriptApi.get_transcript(youtube_id) - transcript_list = YouTubeTranscriptApi.list_transcripts(youtube_id) - transcript = transcript_list.find_transcript(["en"]) - transcript_pieces: List[Dict[str, Any]] = transcript.fetch() + # transcript_list = YouTubeTranscriptApi.list_transcripts(youtube_id) + # transcript = transcript_list.find_transcript(["en"]) + # transcript_pieces: List[Dict[str, Any]] = transcript.fetch() + proxy = os.environ.get("YOUTUBE_TRANSCRIPT_PROXY") + proxies = { 'https': proxy } + transcript_pieces = YouTubeTranscriptApi.get_transcript(youtube_id, proxies = proxies) return transcript_pieces except Exception as e: message = f"Youtube transcript is not available for youtube Id: {youtube_id}" raise Exception(message) -def get_youtube_combined_transcript(youtube_id): - try: - transcript_dict = get_youtube_transcript(youtube_id) - transcript = YouTubeTranscriptApi.get_transcript(youtube_id) - return transcript - except Exception as e: - message = f"Youtube transcript is not available for youtube Id: {youtube_id}" - raise Exception(message) +# def get_youtube_combined_transcript(youtube_id): +# try: +# transcript_dict = get_youtube_transcript(youtube_id) +# transcript = YouTubeTranscriptApi.get_transcript(youtube_id) +# return transcript +# except Exception as e: +# message = f"Youtube transcript is not available for youtube Id: {youtube_id}" +# raise Exception(message) def get_youtube_combined_transcript(youtube_id): try: diff --git a/backend/src/main.py b/backend/src/main.py index 425a24451..3691b7465 100644 --- a/backend/src/main.py +++ b/backend/src/main.py @@ -155,7 +155,7 @@ def create_source_node_graph_url_youtube(graph, model, source_url, source_type): # logging.warning("credntial file path not exist") video_id = parse_qs(urlparse(youtube_url).query).get('v') - print(f'Video Id Youtube: {video_id}') + # google_api_client = GoogleApiClient(service_account_path=Path(file_path)) # youtube_loader_channel = GoogleApiYoutubeLoader( # google_api_client=google_api_client, @@ -165,6 +165,7 @@ def create_source_node_graph_url_youtube(graph, model, source_url, source_type): # page_content = youtube_transcript[0].page_content obj_source_node.file_name = match.group(1)#youtube_transcript[0].metadata["snippet"]["title"] + #obj_source_node.file_name = YouTube(youtube_url).title transcript= get_youtube_combined_transcript(match.group(1)) print(transcript) if transcript==None or len(transcript)==0: @@ -435,7 +436,7 @@ async def processing_source(uri, userName, password, database, model, file_name, else: logging.info('File does not process because it\'s already in Processing status') else: - error_message = "Unable to get the status of docuemnt node." + error_message = "Unable to get the status of document node." logging.error(error_message) raise Exception(error_message) From 6839e522f5494578453ee5dad841519dd4ad5f6f Mon Sep 17 00:00:00 2001 From: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Date: Wed, 23 Oct 2024 14:31:40 +0000 Subject: [PATCH 205/292] update script for async func --- backend/test_integrationqa.py | 80 ++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 34 deletions(-) diff --git a/backend/test_integrationqa.py b/backend/test_integrationqa.py index 0281c91f8..548e9706f 100644 --- a/backend/test_integrationqa.py +++ b/backend/test_integrationqa.py @@ -1,15 +1,19 @@ import json +import asyncio import os import shutil import logging import pandas as pd from datetime import datetime as dt from dotenv import load_dotenv -from score import * +# from score import * from src.main import * from src.QA_integration import QA_RAG from langserve import add_routes - +from src.ragas_eval import get_ragas_metrics +from datasets import Dataset +from ragas import evaluate +from ragas.metrics import answer_relevancy, context_utilization, faithfulness # Load environment variables if needed load_dotenv() import os @@ -57,11 +61,11 @@ def test_graph_from_file_local(model_name): create_source_node_local(graph, model_name, file_name) merged_file_path = os.path.join(MERGED_DIR, file_name) - local_file_result = extract_graph_from_file_local_file( - URI, USERNAME, PASSWORD, DATABASE, model_name, merged_file_path, file_name, '', '',None - ) + local_file_result = asyncio.run(extract_graph_from_file_local_file( + URI, USERNAME, PASSWORD, DATABASE, model_name, merged_file_path, file_name, '', '',None)) logging.info("Local file processing complete") print(local_file_result) + return local_file_result # try: # assert local_file_result['status'] == 'Completed' @@ -72,19 +76,19 @@ def test_graph_from_file_local(model_name): # print("Fail: ", e) # Delete the file after processing - delete_extracted_files(merged_file_path) +# delete_extracted_fiKles(merged_file_path) - return local_file_result + #return local_file_result def test_graph_from_wikipedia(model_name): # try: """Test graph creation from a Wikipedia page.""" - wiki_query = 'https://en.wikipedia.org/wiki/Ram_Mandir' + wiki_query = 'https://en.wikipedia.org/wiki/Berkshire_Hathaway' source_type = 'Wikipedia' - file_name = "Ram_Mandir" + file_name = "Berkshire_Hathaway" create_source_node_graph_url_wikipedia(graph, model_name, wiki_query, source_type) - wiki_result = extract_graph_from_file_Wikipedia(URI, USERNAME, PASSWORD, DATABASE, model_name, file_name, 'en',file_name, '', '',None) + wiki_result = asyncio.run(extract_graph_from_file_Wikipedia(URI, USERNAME, PASSWORD, DATABASE, model_name, file_name, 'en',file_name, '', '',None)) logging.info("Wikipedia test done") print(wiki_result) try: @@ -107,7 +111,7 @@ def test_graph_website(model_name): file_name = [] create_source_node_graph_web_url(graph, model_name, source_url, source_type) - weburl_result = extract_graph_from_web_page(URI, USERNAME, PASSWORD, DATABASE, model_name, source_url,file_name, '', '',None) + weburl_result = asyncio.run(extract_graph_from_web_page(URI, USERNAME, PASSWORD, DATABASE, model_name, source_url,file_name, '', '',None)) logging.info("WebUrl test done") print(weburl_result) @@ -164,9 +168,9 @@ def disconected_nodes(): print(nodes_list[0]["e"]["elementId"]) status = "False" if total_nodes['total']>0: - status = "True" + status = "get_unconnected_nodes_list.. records loaded successfully" else: - status = "False" + status = "get_unconnected_nodes_list ..records not loaded" return nodes_list[0]["e"]["elementId"], status #Test Delete delete_disconnected_nodes list @@ -177,9 +181,9 @@ def delete_disconected_nodes(lst_element_id): result = graphDb_data_Access.delete_unconnected_nodes(json.dumps(lst_element_id)) print(f'delete disconnect api result {result}') if not result: - return "True" + return "delete_unconnected_nodes..Succesfully deleted first index of disconnected nodes" else: - return "False" + return "delete_unconnected_nodes..Unable to delete Nodes" #Test Get Duplicate_nodes def get_duplicate_nodes(): @@ -187,28 +191,34 @@ def get_duplicate_nodes(): graphDb_data_Access = graphDBdataAccess(graph) nodes_list, total_nodes = graphDb_data_Access.get_duplicate_nodes_list() if total_nodes['total']>0: - return "True" + return "Data successfully loaded" else: - return "False" + return "Unable to load data" #Test populate_graph_schema -def test_populate_graph_schema_from_text(model): - result_schema = populate_graph_schema_from_text('When Amazon was founded in 1993 by creator Jeff Benzos, it was mostly an online bookstore. Initially Amazon’s growth was very slow, not turning a profit until over 7 years after its founding. This was thanks to the great momentum provided by the dot-com bubble.', model, True) - print(result_schema) - return result_schema - +def test_populate_graph_schema_from_text(model_name): + schema_text =('Amazon was founded on July 5, 1994, by Jeff Bezos in Bellevue, Washington.The company originally started as an online marketplace for books but gradually expanded its offerings to include a wide range of product categories. This diversification led to it being referred.') + #result_schema='' + try: + result_schema = populate_graph_schema_from_text(schema_text, model_name, True) + print(result_schema) + return result_schema + except Exception as e: + print("Failed to get schema from text", e) + return e def run_tests(): final_list = [] error_list = [] - models = ['openai-gpt-3.5','openai-gpt-4o','openai-gpt-4o-mini','gemini-1.5-pro','gemini 1.5 Flash','azure_ai_gpt_35','azure_ai_gpt_4o','ollama_llama3','ollama','groq_llama3_70b','anthropic_claude_3_5_sonnet','bedrock_claude_3_5_sonnet','fireworks_llama_v3p2_90b'] + + models = ['openai_gpt_3_5','openai_gpt_4o','openai_gpt_4o_mini','azure-ai-gpt-35','azure-ai-gpt-4o','gemini_1_5_pro','gemini_1_5_flash','anthropic-claude-3-5-sonnet','bedrock-claude-3-5-sonnet','groq-llama3-70b','fireworks-llama-v3-70b'] for model_name in models: try: final_list.append(test_graph_from_file_local(model_name)) final_list.append(test_graph_from_wikipedia(model_name)) - final_list.append(test_populate_graph_schema_from_text(model_name)) final_list.append(test_graph_website(model_name)) + final_list.append(test_populate_graph_schema_from_text(model_name)) final_list.append(test_graph_from_youtube_video(model_name)) final_list.append(test_chatbot_qna(model_name)) final_list.append(test_chatbot_qna(model_name, mode='vector')) @@ -219,23 +229,25 @@ def run_tests(): except Exception as e: error_list.append((model_name, str(e))) - # #Compare and log diffrences in graph results - # # compare_graph_results(final_list) # Pass the final_list to comapre_graph_results - # test_populate_graph_schema_from_text('openai-gpt-4o') -# dis_elementid, dis_status = disconected_nodes() -# lst_element_id = [dis_elementid] -# delt = delete_disconected_nodes(lst_element_id) + +# test_populate_graph_schema_from_text('openai-gpt-4o') +#delete diconnected nodes + dis_elementid, dis_status = disconected_nodes() + lst_element_id = [dis_elementid] + delt = delete_disconected_nodes(lst_element_id) # dup = get_duplicate_nodes() print(final_list) - # schma = test_populate_graph_schema_from_text(model) + schma = test_populate_graph_schema_from_text(model_name) # Save final results to CSV df = pd.DataFrame(final_list) print(df) df['execution_date'] = dt.today().strftime('%Y-%m-%d') -# df['disconnected_nodes']=dis_status +#diconnected nodes + df['disconnected_nodes']=dis_status # df['get_duplicate_nodes']=dup -# df['delete_disconected_nodes']=delt - # df['test_populate_graph_schema_from_text'] = schma + + df['delete_disconected_nodes']=delt + df['test_populate_graph_schema_from_text'] = schma df.to_csv(f"Integration_TestResult_{dt.now().strftime('%Y%m%d_%H%M%S')}.csv", index=False) # Save error details to CSV From a5d29fa728121b5c358d4c043535b80aae218fdf Mon Sep 17 00:00:00 2001 From: kaustubh-darekar Date: Thu, 24 Oct 2024 11:59:54 +0530 Subject: [PATCH 206/292] ragas changes for graph retrieval mode. context added in api output (#825) --- backend/example.env | 1 + backend/src/QA_integration.py | 9 +++------ 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/backend/example.env b/backend/example.env index 5d366f21c..7fa3cb480 100644 --- a/backend/example.env +++ b/backend/example.env @@ -2,6 +2,7 @@ OPENAI_API_KEY = "" DIFFBOT_API_KEY = "" GROQ_API_KEY = "" EMBEDDING_MODEL = "all-MiniLM-L6-v2" +RAGAS_EMBEDDING_MODEL = "openai" IS_EMBEDDING = "true" KNN_MIN_SCORE = "0.94" # Enable Gemini (default is False) | Can be False or True diff --git a/backend/src/QA_integration.py b/backend/src/QA_integration.py index 468069531..d56ee5ccb 100644 --- a/backend/src/QA_integration.py +++ b/backend/src/QA_integration.py @@ -434,10 +434,6 @@ def process_chat_response(messages, history, question, model, graph, document_na result = {"sources": list(), "nodedetails": list(), "entities": list()} total_tokens = 0 formatted_docs = "" - - # question = transformed_question if transformed_question else question - # metrics = get_ragas_metrics(question,formatted_docs,content) - # print(metrics) ai_response = AIMessage(content=content) messages.append(ai_response) @@ -580,7 +576,7 @@ def process_graph_response(model, graph, question, messages, history): summarization_thread = threading.Thread(target=summarize_and_log, args=(history, messages, qa_llm)) summarization_thread.start() logging.info("Summarization thread started.") - + metric_details = {"question":question,"contexts":graph_response.get("context", ""),"answer":ai_response_content} result = { "session_id": "", "message": ai_response_content, @@ -589,7 +585,8 @@ def process_graph_response(model, graph, question, messages, history): "cypher_query": graph_response.get("cypher_query", ""), "context": graph_response.get("context", ""), "mode": "graph", - "response_time": 0 + "response_time": 0, + "metric_details": metric_details, }, "user": "chatbot" } From cb59a2a1618cdb0e134c59e22c98800f85804819 Mon Sep 17 00:00:00 2001 From: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Date: Thu, 24 Oct 2024 09:19:00 +0000 Subject: [PATCH 207/292] Remove extract latency from logging and add LIMIT in duplicate nodes --- backend/score.py | 13 +++++++------ backend/src/graphDB_dataAccess.py | 5 +++-- backend/src/main.py | 17 +++++++++-------- .../Deduplication/index.tsx | 8 +++++--- 4 files changed, 24 insertions(+), 19 deletions(-) diff --git a/backend/score.py b/backend/score.py index 48945fb7d..95caa8b0f 100644 --- a/backend/score.py +++ b/backend/score.py @@ -190,22 +190,22 @@ async def extract_knowledge_graph_from_file( if source_type == 'local file': merged_file_path = os.path.join(MERGED_DIR,file_name) logging.info(f'File path:{merged_file_path}') - result = await extract_graph_from_file_local_file(uri, userName, password, database, model, merged_file_path, file_name, allowedNodes, allowedRelationship, retry_condition) + uri_latency, result = await extract_graph_from_file_local_file(uri, userName, password, database, model, merged_file_path, file_name, allowedNodes, allowedRelationship, retry_condition) elif source_type == 's3 bucket' and source_url: - result = await extract_graph_from_file_s3(uri, userName, password, database, model, source_url, aws_access_key_id, aws_secret_access_key, file_name, allowedNodes, allowedRelationship, retry_condition) + uri_latency, result = await extract_graph_from_file_s3(uri, userName, password, database, model, source_url, aws_access_key_id, aws_secret_access_key, file_name, allowedNodes, allowedRelationship, retry_condition) elif source_type == 'web-url': - result = await extract_graph_from_web_page(uri, userName, password, database, model, source_url, file_name, allowedNodes, allowedRelationship, retry_condition) + uri_latency, result = await extract_graph_from_web_page(uri, userName, password, database, model, source_url, file_name, allowedNodes, allowedRelationship, retry_condition) elif source_type == 'youtube' and source_url: - result = await extract_graph_from_file_youtube(uri, userName, password, database, model, source_url, file_name, allowedNodes, allowedRelationship, retry_condition) + uri_latency, result = await extract_graph_from_file_youtube(uri, userName, password, database, model, source_url, file_name, allowedNodes, allowedRelationship, retry_condition) elif source_type == 'Wikipedia' and wiki_query: - result = await extract_graph_from_file_Wikipedia(uri, userName, password, database, model, wiki_query, language, file_name, allowedNodes, allowedRelationship, retry_condition) + uri_latency, result = await extract_graph_from_file_Wikipedia(uri, userName, password, database, model, wiki_query, language, file_name, allowedNodes, allowedRelationship, retry_condition) elif source_type == 'gcs bucket' and gcs_bucket_name: - result = await extract_graph_from_file_gcs(uri, userName, password, database, model, gcs_project_id, gcs_bucket_name, gcs_bucket_folder, gcs_blob_filename, access_token, file_name, allowedNodes, allowedRelationship, retry_condition) + uri_latency, result = await extract_graph_from_file_gcs(uri, userName, password, database, model, gcs_project_id, gcs_bucket_name, gcs_bucket_folder, gcs_blob_filename, access_token, file_name, allowedNodes, allowedRelationship, retry_condition) else: return create_api_response('Failed',message='source_type is other than accepted source') extract_api_time = time.time() - start_time @@ -218,6 +218,7 @@ async def extract_knowledge_graph_from_file( result['logging_time'] = formatted_time(datetime.now(timezone.utc)) result['elapsed_api_time'] = f'{extract_api_time:.2f}' logger.log_struct(result, "INFO") + result.update(uri_latency) logging.info(f"extraction completed in {extract_api_time:.2f} seconds for file name {file_name}") return create_api_response('Success', data=result, file_source= source_type) except Exception as e: diff --git a/backend/src/graphDB_dataAccess.py b/backend/src/graphDB_dataAccess.py index f5d1b228c..189d581a6 100644 --- a/backend/src/graphDB_dataAccess.py +++ b/backend/src/graphDB_dataAccess.py @@ -390,13 +390,14 @@ def get_duplicate_nodes_list(self): [s in similar | s {.id, .description, labels:labels(s), elementId: elementId(s)}] as similar, collect(distinct doc.fileName) as documents, count(distinct c) as chunkConnections ORDER BY e.id ASC + LIMIT 100 """ - return_query_duplicate_nodes_total = "RETURN COUNT(DISTINCT(n)) as total" + total_duplicate_nodes = "RETURN COUNT(DISTINCT(n)) as total" param = {"duplicate_score_value": score_value, "duplicate_text_distance" : text_distance} nodes_list = self.execute_query(query_duplicate_nodes.format(return_statement=return_query_duplicate_nodes),param=param) - total_nodes = self.execute_query(query_duplicate_nodes.format(return_statement=return_query_duplicate_nodes_total),param=param) + total_nodes = self.execute_query(query_duplicate_nodes.format(return_statement=total_duplicate_nodes),param=param) return nodes_list, total_nodes[0] def merge_duplicate_nodes(self,duplicate_nodes_list): diff --git a/backend/src/main.py b/backend/src/main.py index 3691b7465..05f83f073 100644 --- a/backend/src/main.py +++ b/backend/src/main.py @@ -424,15 +424,16 @@ async def processing_source(uri, userName, password, database, model, file_name, uri_latency["Per_entity_latency"] = 'N/A' else: uri_latency["Per_entity_latency"] = f'{int(processing_source_func)/node_count}/s' - uri_latency["fileName"] = file_name - uri_latency["nodeCount"] = node_count - uri_latency["relationshipCount"] = rel_count - uri_latency["total_processing_time"] = round(processed_time.total_seconds(),2) - uri_latency["status"] = job_status - uri_latency["model"] = model - uri_latency["success_count"] = 1 + response = {} + response["fileName"] = file_name + response["nodeCount"] = node_count + response["relationshipCount"] = rel_count + response["total_processing_time"] = round(processed_time.total_seconds(),2) + response["status"] = job_status + response["model"] = model + response["success_count"] = 1 - return uri_latency + return uri_latency, response else: logging.info('File does not process because it\'s already in Processing status') else: diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx index 420fbe590..1e6b0c213 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx @@ -45,7 +45,7 @@ export default function DeduplicationTab() { const [neoRels, setNeoRels] = useState([]); const [openGraphView, setOpenGraphView] = useState(false); const [viewPoint, setViewPoint] = useState(''); - + const [nodesCount, setNodesCount] = useState(0); const fetchDuplicateNodes = useCallback(async () => { try { setLoading(true); @@ -56,6 +56,8 @@ export default function DeduplicationTab() { } if (duplicateNodesData.data.data.length) { setDuplicateNodes(duplicateNodesData.data.data); + //@ts-ignore + setNodesCount(duplicateNodesData.data.message.total) } else { setDuplicateNodes([]); } @@ -272,9 +274,9 @@ export default function DeduplicationTab() { accuracy and clarity of your knowledge graph. - {duplicateNodes.length > 0 && ( + {nodesCount > 0 && ( - Total Duplicate Nodes: {duplicateNodes.length} + Total Duplicate Nodes: {nodesCount} )} From 93d7f3baa42e3ba804264e4044efb8c6cb94414f Mon Sep 17 00:00:00 2001 From: kaustubh-darekar Date: Thu, 24 Oct 2024 15:28:46 +0530 Subject: [PATCH 208/292] Document updates (#828) * document updated with ragas evaluation information * formatting changes * chatbot api documentation updated * api details added in document * function name changed for drop create vector index api --- README.md | 2 +- backend/score.py | 2 +- docs/backend/backend_docs.adoc | 228 ++++++++++++++++++++++++++++++--- 3 files changed, 212 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 01342a8a4..e820f04a9 100644 --- a/README.md +++ b/README.md @@ -153,7 +153,7 @@ Allow unauthenticated request : Yes | GCS_FILE_CACHE | Optional | False | If set to True, will save the files to process into GCS. If set to False, will save the files locally | | ENTITY_EMBEDDING | Optional | False | If set to True, It will add embeddings for each entity in database | | LLM_MODEL_CONFIG_ollama_ | Optional | | Set ollama config as - model_name,model_local_url for local deployments | - +| RAGAS_EMBEDDING_MODEL | Optional | openai | embedding model used by ragas evaluation framework | diff --git a/backend/score.py b/backend/score.py index 95caa8b0f..f7b8c4082 100644 --- a/backend/score.py +++ b/backend/score.py @@ -749,7 +749,7 @@ async def merge_duplicate_nodes(uri=Form(), userName=Form(), password=Form(), da gc.collect() @app.post("/drop_create_vector_index") -async def merge_duplicate_nodes(uri=Form(), userName=Form(), password=Form(), database=Form(), isVectorIndexExist=Form()): +async def drop_create_vector_index(uri=Form(), userName=Form(), password=Form(), database=Form(), isVectorIndexExist=Form()): try: payload_json_obj = {'api_name':'drop_create_vector_index', 'db_url':uri, 'userName':userName, 'database':database, 'isVectorIndexExist':isVectorIndexExist, 'logging_time': formatted_time(datetime.now(timezone.utc))} diff --git a/docs/backend/backend_docs.adoc b/docs/backend/backend_docs.adoc index 91b39260c..3924e2a17 100644 --- a/docs/backend/backend_docs.adoc +++ b/docs/backend/backend_docs.adoc @@ -374,6 +374,8 @@ The API responsible for a chatbot system designed to leverage multiple AI models * `model`= LLM model * `question`= User query for the chatbot * `session_id`= Session ID used to maintain the history of chats during the user's connection +* `document_names`= File name/names for which user wants to question +* `mode`= Retrieval mode used for answer generation **Response :** [source,json,indent=0] @@ -381,26 +383,51 @@ The API responsible for a chatbot system designed to leverage multiple AI models { "status": "Success", "data": { - "session_id": "0901", - "message": "Fibrosis, also known as fibrotic scarring, is a pathological wound healing process where connective tissue replaces normal parenchymal tissue." + "session_id": "d345d9b6-f8f1-40c0-b585-280c998b9752", + "message": "Google DeepMind is a British-American artificial intelligence research laboratory that focuses on developing advanced AI technologies. It is known for creating neural network models capable of playing video games and board games, such as the AlphaGo program, which famously defeated a world champion Go player. DeepMind also works on general-purpose AI systems, like AlphaZero, which can play multiple games at a high level. Additionally, the company has been involved in AI safety work and has established an ethics board to guide its AI development.", "info": { "sources": [ - { - "source_name": "https://en.wikipedia.org/wiki/Fibrosis", - "page_numbers": [], - "start_time": [] - } + "https://en.wikipedia.org/wiki/Google_DeepMind" ], - "model": "gpt-4o", - "chunkids": [ - "54d8c0dbefb67f1ed3f6939d59267e1ff557a94c", - "4cc02ee8419706c8decdf71ab0d3896aad5c7dca", - "266ce95311bb1921791b4f1cd29a48d433027139", - "11e19513247e1e396475728fa6a197695045b248", - "8bafa01b6d851f70822bcb86863e485e1785a64c" - ], - "total_tokens": 2213, - "response_time": 10.17 + "model": "gpt-4o-2024-08-06", + "nodedetails": { + "chunkdetails": [ + { + "id": "80b30de81d6c1dca5973587b538887de8f47237d", + "score": 0.8614 + }, + { + "id": "419cee50cef9aba9c2204f2a7a17bfe84fb1df20", + "score": 0.8306 + }, + { + "id": "9daf80b62be569ace896d1945c7b25a7fcce9027", + "score": 0.827 + }, + { + "id": "36a1441279bf19feb5498d9a0ecfcebefac1d1f5", + "score": 0.8232 + }, + { + "id": "31a8234c4ab3c5fff8febb4264a5a041e1f21c36", + "score": 0.8181 + } + ], + "entitydetails": [], + "communitydetails": [] + }, + "total_tokens": 1713, + "response_time": 7.22, + "mode": "vector", + "entities": { + "entityids": [], + "relationshipids": [] + }, + "metric_details": { + "question": "what does google deepmind do?", + "contexts": "Document start\nThis Document belongs to the source https://en.wikipedia.org/wiki/Google_DeepMind\nContent: developed by Google DeepMind. == References == == Further reading == == External links == Official website\n----\nDeepMind Technologies Limited, also known by its trade name Google DeepMind, is a British-American artificial intelligence research laboratory which serves as a subsidiary of Google. Founded in the UK in 2010, it was acquired by Google in 2014 and merged with Google AIs Google Brain division to become Google DeepMind in April 2023.\nDocument end\n", + "answer": "Google DeepMind is a British-American artificial intelligence research laboratory that focuses on developing advanced AI technologies. It is known for creating neural network models capable of playing video games and board games, such as the AlphaGo program, which famously defeated a world champion Go player. DeepMind also works on general-purpose AI systems, like AlphaZero, which can play multiple games at a high level. Additionally, the company has been involved in AI safety work and has established an ethics board to guide its AI development." + } }, "user": "chatbot" } @@ -699,7 +726,7 @@ The API is used to delete unconnected entities from database. .... -== Decisions +==== Decisions * Process only 1st page of Wikipedia * Split document content into chunks of size 200 and overlap of 20 @@ -709,3 +736,168 @@ The API is used to delete unconnected entities from database. ** Embedding model ** minimum score for KNN graph ** Uploaded file storage location (GCS bucket or container) + + +=== Get duplicate nodes +---- +POST /get_duplicate_nodes +---- + +The API is used to fetch duplicate entities from database. + +**API Parameters :** + +* `uri`=Neo4j uri, +* `userName`= Neo4j db username, +* `password`= Neo4j db password, +* `database`= Neo4j database name, + + +**Response :** +[source,json,indent=0] +.... +{ + "status": "Success", + "data": [ + { + "e": { + "id": "13 September 2024", + "elementId": "4:b104b2e7-e2ed-4902-b78b-7ad1518ca04f:14007", + "communities": [ + 2969, + 383, + 81 + ], + "labels": [ + "__Entity__", + "Date" + ], + "embedding": null + }, + "similar": [ + { + "id": "20 September 2024", + "elementId": "4:b104b2e7-e2ed-4902-b78b-7ad1518ca04f:14153", + "description": null, + "labels": [ + "__Entity__", + "Date" + ] + } + ], + "documents": [], + "chunkConnections": 0 + } + ], + "message": { + "total": 1 + } +} +.... + + +=== Merge duplicate nodes +---- +POST /merge_duplicate_nodes +---- + +The API is used to merge duplicate entities from database selected by user. + +**API Parameters :** + +* `uri`=Neo4j uri, +* `userName`= Neo4j db username, +* `password`= Neo4j db password, +* `database`= Neo4j database name, +* `duplicate_nodes_list`= selected entities list to merge of with similar entities. + +**Response :** +[source,json,indent=0] +.... +{ + "status": "Success", + "data": [ + { + "totalMerged": 2 + } + ], + "message": "Duplicate entities merged successfully" +} +.... +=== drop +---- +POST /retry_processing +---- + +The API is used to drop and create the vector index when vector index dimesion are different. + +**API Parameters :** + +* `uri`=Neo4j uri, +* `userName`= Neo4j db username, +* `password`= Neo4j db password, +* `database`= Neo4j database name, +* `isVectorIndexExist`= True or False based on whether vector index exist in database, + +**Response :** +[source,json,indent=0] +.... +{ + "status": "Success", + "message": "Drop and Re-Create vector index succesfully" +} +.... + +=== Reprocess document +---- +POST /retry_processing +---- + +The API is used to reprocess document. + +**API Parameters :** + +* `uri`=Neo4j uri, +* `userName`= Neo4j db username, +* `password`= Neo4j db password, +* `database`= Neo4j database name, +* `file_name`= The name of the file which needs to be reprocessed, +* `retry_condition`= reprocessing condition whether to just start from beginning or delete created entitities and reprocess, + +**Response :** +[source,json,indent=0] +.... +{ + "status": "Success", + "message": "Status set to Reprocess for filename : Alphabet.pdf" +} +.... + +=== Evaluate response +---- +POST /metric +---- + +The API responsible for a evaluating chatbot responses on the basis of different metrics such as faithfulness and answer relevancy. This utilises RAGAS library to calculate these metrics. + +**API Parameters :** + +* `question`= User query for the chatbot +* `context`= context retrieved by retrieval mode used for answer generation +* `answer`= answer generated by chatbot +* `model`= LLM model +* `mode`= Retrieval mode used for answer generationRetrieval mode used for answer generation + +**Response :** +[source,json,indent=0] +.... +{ + "status": "Success", + "data": { + "graph+vector+fulltext": { + "faithfulness": 1.0, + "answer_relevancy": 0.9699 + } + } +} +.... \ No newline at end of file From 0d2882c912a32748647e823b0a5ce313da336bde Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Thu, 24 Oct 2024 17:02:50 +0530 Subject: [PATCH 209/292] Update README.md --- README.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/README.md b/README.md index e820f04a9..8d05f10fa 100644 --- a/README.md +++ b/README.md @@ -156,6 +156,32 @@ Allow unauthenticated request : Yes | RAGAS_EMBEDDING_MODEL | Optional | openai | embedding model used by ragas evaluation framework | +## For local llms (Ollama) +1. Pull the docker imgage of ollama +```bash +docker pull ollama/ollama +``` +2. Run the ollama docker image +```bash +docker run -d -v ollama:/root/.ollama -p 11434:11434 --name ollama ollama/ollama +``` +3. Execute any llm model ex🦙3 +```bash +docker exec -it ollama ollama run llama3 +``` +4. Configure env variable in docker compose or backend enviournment. +```env +LLM_MODEL_CONFIG_ollama_ +#example +LLM_MODEL_CONFIG_ollama_llama3=${LLM_MODEL_CONFIG_ollama_llama3-llama3, +http://host.docker.internal:11434} +``` +5. Configure the backend API url +```env +VITE_BACKEND_API_URL=${VITE_BACKEND_API_URL-backendurl} +``` +6. Open the application in browser and select the ollama model for the extraction. +7. Enjoy Graph Building. ## Usage From 6a6dc051c25e819a70f3586dc0d18b79cf4bb242 Mon Sep 17 00:00:00 2001 From: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Date: Thu, 24 Oct 2024 17:07:22 +0530 Subject: [PATCH 210/292] updated api structire in docs (#827) --- docs/backend/backend_docs.adoc | 220 ++++++++++++++++++++++----------- 1 file changed, 149 insertions(+), 71 deletions(-) diff --git a/docs/backend/backend_docs.adoc b/docs/backend/backend_docs.adoc index 3924e2a17..8016fd481 100644 --- a/docs/backend/backend_docs.adoc +++ b/docs/backend/backend_docs.adoc @@ -22,9 +22,15 @@ Neo4j database connection on frontend is done with this API. [source,json,indent=0] ---- { - "status":"Success", - "message":"Connection Successful" -} + "status": "Success", + "data": { + "db_vector_dimension": 384, + "application_dimension": 384, + "message": "Connection Successful", + "gds_status": true, + "write_access": true, + "elapsed_api_time": "5.48" + } ---- @@ -361,10 +367,12 @@ The API responsible for a chatbot system designed to leverage multiple AI models **Components :** -** Embedding Models - Includes OpenAI Embeddings, VertexAI Embeddings, and SentenceTransformer Embeddings to support vector-based query operations. -** AI Models - OpenAI GPT 3.5, GPT 4o, Gemini Pro, Gemini 1.5 Pro and Groq llama3 can be configured for the chatbot backend to generate responses and process natural language. +** Embedding Models - Includes OpenAI Embeddings, VertexAI Embeddings, and SentenceTransformer Embeddings(Default) to support vector-based query operations. +** AI Models - OpenAI GPT 3.5, GPT 4o, GPT 40 mini, gemini_1.5_flash can be configured for the chatbot backend to generate responses and process natural language. ** Graph Database (Neo4jGraph) - Manages interactions with the Neo4j database, retrieving, and storing conversation histories. ** Response Generation - Utilizes Vector Embeddings from the Neo4j database, chat history, and the knowledge base of the LLM used. +** Chat Modes - Vector , Graph, Vector + Graph, Fulltext, Vector + Graph+Fulltext, Entity Search + Vector, Global search Vector + **API Parameters :** @@ -373,9 +381,9 @@ The API responsible for a chatbot system designed to leverage multiple AI models * `password`= Neo4j database password * `model`= LLM model * `question`= User query for the chatbot -* `session_id`= Session ID used to maintain the history of chats during the user's connection -* `document_names`= File name/names for which user wants to question -* `mode`= Retrieval mode used for answer generation +* `session_id`= Session ID used to maintain the history of chats during the user's connection +* `mode` = chat mode to use +* `document_names` = the names of documents to be filtered works for vector mode and vector+Graph mode **Response :** [source,json,indent=0] @@ -383,50 +391,45 @@ The API responsible for a chatbot system designed to leverage multiple AI models { "status": "Success", "data": { - "session_id": "d345d9b6-f8f1-40c0-b585-280c998b9752", - "message": "Google DeepMind is a British-American artificial intelligence research laboratory that focuses on developing advanced AI technologies. It is known for creating neural network models capable of playing video games and board games, such as the AlphaGo program, which famously defeated a world champion Go player. DeepMind also works on general-purpose AI systems, like AlphaZero, which can play multiple games at a high level. Additionally, the company has been involved in AI safety work and has established an ethics board to guide its AI development.", + + "session_id": "0cbd04a8-abc3-4776-b393-6a9a2cea36b3", + "message": "response generated by the chat", "info": { "sources": [ - "https://en.wikipedia.org/wiki/Google_DeepMind" + "About Amazon.pdf" ], "model": "gpt-4o-2024-08-06", "nodedetails": { "chunkdetails": [ { - "id": "80b30de81d6c1dca5973587b538887de8f47237d", - "score": 0.8614 + "id": "73bc9c9170bcd807d2fa87d87a0eeb3d82f95160", + "score": 1.0 }, { - "id": "419cee50cef9aba9c2204f2a7a17bfe84fb1df20", - "score": 0.8306 - }, - { - "id": "9daf80b62be569ace896d1945c7b25a7fcce9027", - "score": 0.827 - }, - { - "id": "36a1441279bf19feb5498d9a0ecfcebefac1d1f5", - "score": 0.8232 - }, - { - "id": "31a8234c4ab3c5fff8febb4264a5a041e1f21c36", - "score": 0.8181 + "id": "de5486776978353c9f8ac530bcff33eeecbdbbad", + "score": 0.9425 } ], "entitydetails": [], "communitydetails": [] }, - "total_tokens": 1713, - "response_time": 7.22, - "mode": "vector", + "total_tokens": 4575, + "response_time": 17.19, + "mode": "graph_vector_fulltext", "entities": { - "entityids": [], - "relationshipids": [] + "entityids": [ + "4:98e5e9bb-8095-440d-9462-03985fed2fa2:307", + "4:98e5e9bb-8095-440d-9462-03985fed2fa2:1877", + ], + "relationshipids": [ + "5:98e5e9bb-8095-440d-9462-03985fed2fa2:8072566611095062357", + "5:98e5e9bb-8095-440d-9462-03985fed2fa2:8072566508015847224" + ] }, "metric_details": { - "question": "what does google deepmind do?", - "contexts": "Document start\nThis Document belongs to the source https://en.wikipedia.org/wiki/Google_DeepMind\nContent: developed by Google DeepMind. == References == == Further reading == == External links == Official website\n----\nDeepMind Technologies Limited, also known by its trade name Google DeepMind, is a British-American artificial intelligence research laboratory which serves as a subsidiary of Google. Founded in the UK in 2010, it was acquired by Google in 2014 and merged with Google AIs Google Brain division to become Google DeepMind in April 2023.\nDocument end\n", - "answer": "Google DeepMind is a British-American artificial intelligence research laboratory that focuses on developing advanced AI technologies. It is known for creating neural network models capable of playing video games and board games, such as the AlphaGo program, which famously defeated a world champion Go player. DeepMind also works on general-purpose AI systems, like AlphaZero, which can play multiple games at a high level. Additionally, the company has been involved in AI safety work and has established an ethics board to guide its AI development." + "question": "tell me about amazon ", + "contexts": "context sent to LLM" + "answer": "response generated by the LLM" } }, "user": "chatbot" @@ -447,7 +450,8 @@ This API is used to get the entities and relations associated with a particular * `userName`= Neo4j db username, * `password`= Neo4j db password, * `database`= Neo4j database name -* `chunk_ids` = Chunk ids of document +* `nodedetails` = Node element id's to get information(chunks,entities,communities) +* `entities` = entities received from the retriver for graph based modes **Response :** @@ -458,42 +462,51 @@ This API is used to get the entities and relations associated with a particular "data": { "nodes": [ { - "element_id": "4:a69712a5-1102-40da-a96d-70c1143ea8e5:73267", + "element_id": "4:98e5e9bb-8095-440d-9462-03985fed2fa2:307", "labels": [ - "Condition" + "Company" ], "properties": { - "id": "Fibrosis" + "id": "Amazon", + "description": "Initially an online bookstore, Amazon has transformed into a $48 billion retail giant, offering products in over forty categories, from books and electronics to groceries. Today, it operates as a logistics platform, a search engine, an Internet advertising platform, an e-commerce platform, and an IT platform." } - }, - + } ], "relationships": [ { - "element_id": "5:a69712a5-1102-40da-a96d-70c1143ea8e5:1153057844048764467", - "type": "AFFECTS", - "start_node_element_id": "4:a69712a5-1102-40da-a96d-70c1143ea8e5:73267", - "end_node_element_id": "4:a69712a5-1102-40da-a96d-70c1143ea8e5:73282" - }, - { - "element_id": "5:a69712a5-1102-40da-a96d-70c1143ea8e5:1155309643862449715", - "type": "AFFECTS", - "start_node_element_id": "4:a69712a5-1102-40da-a96d-70c1143ea8e5:73267", - "end_node_element_id": "4:a69712a5-1102-40da-a96d-70c1143ea8e5:73294" - }, + "element_id": "5:98e5e9bb-8095-440d-9462-03985fed2fa2:6917952339617775946", + "type": "OFFERS", + "start_node_element_id": "4:98e5e9bb-8095-440d-9462-03985fed2fa2:307", + "end_node_element_id": "4:98e5e9bb-8095-440d-9462-03985fed2fa2:330" + } ], "chunk_data": [ { - "id": "54d8c0dbefb67f1ed3f6939d59267e1ff557a94c", - "position": 1, - "text": "Fibrosis, also known as fibrotic scarring, is a pathological wound healing ...", - "content_offset": 0, - "fileName": "fibrosis", - "length": 1002, + "element_id": "4:98e5e9bb-8095-440d-9462-03985fed2fa2:14", + "id": "d1e92be81a0872d621242cee9fed69d14b0cd68d", + "position": 13, + "text": " 6 eBay, operating as the biggest online auction house and focusing as a service provider, employs cost leadership strategy by solely operating e-commerce as an intermediary without holding any inventories or physical infrastructures. It also applies a differentiation strategy by providing a ....", + "content_offset": 9886, + "fileName": "About Amazon.pdf", + "page_number": 7, + "length": 1024, + "fileSource": "local file", "embedding": null } + ], + "community_data": [ + { + "element_id": "4:98e5e9bb-8095-440d-9462-03985fed2fa2:1026", + "summary": "Google, led by CEO Sundar Pichai, is actively involved in various business and product initiatives.", + "id": "0-311", + "level": 0, + "weight": 7, + "embedding": null, + "community_rank": 1 + } ] - } + }, + "message": "Total elapsed API time 3.75" } .... @@ -551,6 +564,63 @@ This API is used to view graph for a particular file. } .... +=== Get neighbour nodes +---- +POST /get_neighbours +---- + +This API is used to retrive the neighbor nodes of the given element id of the node. + +**API Parameters :** + +* `uri`=Neo4j uri, +* `userName`= Neo4j db username, +* `password`= Neo4j db password, +* `database`= Neo4j database name, +* `elementId` = Element id of the node to retrive its neighbours + + +**Response :** +[source,json,indent=0] +.... +{ + "status": "Success", + "data": { + "nodes": [ + { + "summary": null, + "element_id": "4:98e5e9bb-8095-440d-9462-03985fed2fa2:3", + "id": "73bc9c9170bcd807d2fa87d87a0eeb3d82f95160", + "position": 2, + "text": null, + "content_offset": 186, + "labels": [ + "Chunk" + ], + "page_number": 2, + "fileName": "About Amazon.pdf", + "length": 904, + "properties": { + "id": "73bc9c9170bcd807d2fa87d87a0eeb3d82f95160" + }, + "embedding": null + } + ], + "relationships": [ + { + "element_id": "5:98e5e9bb-8095-440d-9462-03985fed2fa2:1175445000301838339", + "end_node_element_id": "4:98e5e9bb-8095-440d-9462-03985fed2fa2:18", + "start_node_element_id": "4:98e5e9bb-8095-440d-9462-03985fed2fa2:3", + "type": "HAS_ENTITY" + }, + ] + }, + "message": "Total elapsed API time 0.24" +} +.... + + + === Clear chat history ---- POST /clear_chat_bot @@ -848,28 +918,36 @@ The API is used to drop and create the vector index when vector index dimesion a } .... -=== Reprocess document +=== Reprocessing of sources ---- POST /retry_processing ---- - -The API is used to reprocess document. - + +This API is used to reprocess cancelled, completed or failed file sources. +Users have 3 options to reprocess files: + +* Start from begnning - In this condition file will be processed from the begnning i.e. 1st chunk again. +* Delete entities and start from begnning - If the file source is already processed and have any existing nodes and relations then those will be deleted and file will be reprocessed from the 1st chunk. +* Start from last processed postion - Cancelled or failed files will be processed from the last successfully processed chunk position. This option is not available for completed files. + +Ones the status is set to 'Reprocess', user can again click on Generate graph to process the file for knowledge graph creation. + **API Parameters :** - -* `uri`=Neo4j uri, -* `userName`= Neo4j db username, -* `password`= Neo4j db password, + +* `uri`=Neo4j uri, +* `userName`= Neo4j db username, +* `password`= Neo4j db password, * `database`= Neo4j database name, -* `file_name`= The name of the file which needs to be reprocessed, -* `retry_condition`= reprocessing condition whether to just start from beginning or delete created entitities and reprocess, - +* `file_name`= Name of the file which user want to reprocess. +* `retry_condition` = One of the above 3 conditions which is selected for reprocessing. + + **Response :** [source,json,indent=0] .... { "status": "Success", - "message": "Status set to Reprocess for filename : Alphabet.pdf" + "message": "Status set to Reprocess for filename : $filename" } .... From 29ef09b7ec0525cc1cb43aedecc68da21488dbd1 Mon Sep 17 00:00:00 2001 From: karanchellani <142801957+karanchellani@users.noreply.github.com> Date: Thu, 24 Oct 2024 17:14:42 +0530 Subject: [PATCH 211/292] Update backend_docs.adoc --- docs/backend/backend_docs.adoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/backend/backend_docs.adoc b/docs/backend/backend_docs.adoc index 8016fd481..2591ac47e 100644 --- a/docs/backend/backend_docs.adoc +++ b/docs/backend/backend_docs.adoc @@ -894,9 +894,9 @@ The API is used to merge duplicate entities from database selected by user. "message": "Duplicate entities merged successfully" } .... -=== drop +=== Drop and create vector index ---- -POST /retry_processing +POST /drop_create_vector_index ---- The API is used to drop and create the vector index when vector index dimesion are different. @@ -978,4 +978,4 @@ The API responsible for a evaluating chatbot responses on the basis of different } } } -.... \ No newline at end of file +.... From c5cd025bf92adac81d4e7120ca9f93f8ea00c363 Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Thu, 24 Oct 2024 17:18:19 +0530 Subject: [PATCH 212/292] 821 llm model listing (#823) * added logic for document filters * LLM models * message change * link added * removed the text --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> --- backend/src/QA_integration.py | 22 ++++++++++++++++++-- docker-compose.yml | 1 + example.env | 1 + frontend/Dockerfile | 2 ++ frontend/example.env | 1 + frontend/src/components/Content.tsx | 30 +++++++++++++--------------- frontend/src/components/Dropdown.tsx | 13 +++++++++++- frontend/src/utils/Constants.ts | 5 +++++ 8 files changed, 56 insertions(+), 19 deletions(-) diff --git a/backend/src/QA_integration.py b/backend/src/QA_integration.py index d56ee5ccb..b7fcbd665 100644 --- a/backend/src/QA_integration.py +++ b/backend/src/QA_integration.py @@ -390,7 +390,7 @@ def get_neo4j_retriever(graph, document_names,chat_mode_settings, score_threshol try: neo_db = initialize_neo4j_vector(graph, chat_mode_settings) - document_names= list(map(str.strip, json.loads(document_names))) + # document_names= list(map(str.strip, json.loads(document_names))) search_k = chat_mode_settings["top_k"] retriever = create_retriever(neo_db, document_names,chat_mode_settings, search_k, score_threshold) return retriever @@ -656,7 +656,25 @@ def QA_RAG(graph,model, question, document_names, session_id, mode, write_access result = process_graph_response(model, graph, question, messages, history) else: chat_mode_settings = get_chat_mode_settings(mode=mode) - result = process_chat_response(messages,history, question, model, graph, document_names,chat_mode_settings) + document_names= list(map(str.strip, json.loads(document_names))) + if document_names and not chat_mode_settings["document_filter"]: + result = { + "session_id": "", + "message": "This chat mode does support document selection", + "info": { + "sources": [], + "model": "", + "nodedetails": [], + "total_tokens": 0, + "response_time": 0, + "mode": chat_mode_settings["mode"], + "entities": [], + "metric_details": [], + }, + "user": "chatbot" + } + else: + result = process_chat_response(messages,history, question, model, graph, document_names,chat_mode_settings) result["session_id"] = session_id diff --git a/docker-compose.yml b/docker-compose.yml index afc87b848..ea6d2c050 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -62,6 +62,7 @@ services: - VITE_ENV=${VITE_ENV-DEV} - VITE_CHAT_MODES=${VITE_CHAT_MODES-} - VITE_BATCH_SIZE=${VITE_BATCH_SIZE-2} + - VITE_LLM_MODELS_PROD=${VITE_LLM_MODELS_PROD-openai_gpt_4o,openai_gpt_4o_mini,diffbot,gemini_1.5_flash} volumes: - ./frontend:/app - /app/node_modules diff --git a/example.env b/example.env index 227c51904..6b542daf1 100644 --- a/example.env +++ b/example.env @@ -31,3 +31,4 @@ VITE_CHUNK_SIZE=5242880 VITE_GOOGLE_CLIENT_ID="" VITE_CHAT_MODES="" VITE_BATCH_SIZE=2 +VITE_LLM_MODELS_PROD="openai_gpt_4o,openai_gpt_4o_mini,diffbot,gemini_1.5_flash" diff --git a/frontend/Dockerfile b/frontend/Dockerfile index c3a7c1c82..3053e1ba9 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -12,6 +12,7 @@ ARG VITE_CHUNK_SIZE=5242880 ARG VITE_CHAT_MODES="" ARG VITE_ENV="DEV" ARG VITE_BATCH_SIZE=2 +ARG VITE_LLM_MODELS_PROD="openai_gpt_4o,openai_gpt_4o_mini,diffbot,gemini_1.5_flash" WORKDIR /app COPY package.json yarn.lock ./ @@ -28,6 +29,7 @@ RUN VITE_BACKEND_API_URL=$VITE_BACKEND_API_URL \ VITE_LARGE_FILE_SIZE=${VITE_LARGE_FILE_SIZE} \ VITE_CHAT_MODES=$VITE_CHAT_MODES \ VITE_BATCH_SIZE=$VITE_BATCH_SIZE \ + VITE_LLM_MODELS_PROD=$VITE_LLM_MODELS_PROD \ yarn run build # Step 2: Serve the application using Nginx diff --git a/frontend/example.env b/frontend/example.env index 9bc5bc0d5..4063fbc37 100644 --- a/frontend/example.env +++ b/frontend/example.env @@ -9,3 +9,4 @@ VITE_LARGE_FILE_SIZE=5242880 VITE_GOOGLE_CLIENT_ID="" VITE_CHAT_MODES="" VITE_BATCH_SIZE=2 +VITE_LLM_MODELS_PROD="openai_gpt_4o,openai_gpt_4o_mini,diffbot,gemini_1.5_flash" diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index c5dceaf36..3f6be20fb 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -521,9 +521,8 @@ const Content: React.FC = ({ const handleOpenGraphClick = () => { const bloomUrl = process.env.VITE_BLOOM_URL; const uriCoded = userCredentials?.uri.replace(/:\d+$/, ''); - const connectURL = `${uriCoded?.split('//')[0]}//${userCredentials?.userName}@${uriCoded?.split('//')[1]}:${ - userCredentials?.port ?? '7687' - }`; + const connectURL = `${uriCoded?.split('//')[0]}//${userCredentials?.userName}@${uriCoded?.split('//')[1]}:${userCredentials?.port ?? '7687' + }`; const encodedURL = encodeURIComponent(connectURL); const replacedUrl = bloomUrl?.replace('{CONNECT_URL}', encodedURL); window.open(replacedUrl, '_blank'); @@ -533,10 +532,10 @@ const Content: React.FC = ({ isLeftExpanded && isRightExpanded ? 'contentWithExpansion' : isRightExpanded - ? 'contentWithChatBot' - : !isLeftExpanded && !isRightExpanded - ? 'w-[calc(100%-128px)]' - : 'contentWithDropzoneExpansion'; + ? 'contentWithChatBot' + : !isLeftExpanded && !isRightExpanded + ? 'w-[calc(100%-128px)]' + : 'contentWithDropzoneExpansion'; const handleGraphView = () => { setOpenGraphView(true); @@ -568,12 +567,12 @@ const Content: React.FC = ({ return prev.map((f) => { return f.name === filename ? { - ...f, - status: 'Reprocess', - processingProgress: isStartFromBegining ? 0 : f.processingProgress, - nodesCount: isStartFromBegining ? 0 : f.nodesCount, - relationshipCount: isStartFromBegining ? 0 : f.relationshipsCount, - } + ...f, + status: 'Reprocess', + processingProgress: isStartFromBegining ? 0 : f.processingProgress, + nodesCount: isStartFromBegining ? 0 : f.nodesCount, + relationshipCount: isStartFromBegining ? 0 : f.relationshipsCount, + } : f; }); }); @@ -862,9 +861,8 @@ const Content: React.FC = ({ handleGenerateGraph={processWaitingFilesOnRefresh} > diff --git a/frontend/src/components/Dropdown.tsx b/frontend/src/components/Dropdown.tsx index 087e0d71c..8c434309f 100644 --- a/frontend/src/components/Dropdown.tsx +++ b/frontend/src/components/Dropdown.tsx @@ -2,7 +2,7 @@ import { Dropdown, Tip } from '@neo4j-ndl/react'; import { OptionType, ReusableDropdownProps } from '../types'; import { memo, useMemo, useReducer } from 'react'; import { capitalize, capitalizeWithUnderscore } from '../utils/Utils'; - +// import { LLMDropdownLabel } from '../utils/Constants'; const DropdownComponent: React.FC = ({ options, placeholder, @@ -14,6 +14,8 @@ const DropdownComponent: React.FC = ({ value, }) => { const [disableTooltip, toggleDisableState] = useReducer((state) => !state, false); + const isProdEnv = process.env.VITE_ENV === 'PROD'; + const supportedModels = process.env.VITE_LLM_MODELS_PROD; const handleChange = (selectedOption: OptionType | null | void) => { onSelect(selectedOption); }; @@ -33,9 +35,11 @@ const DropdownComponent: React.FC = ({ const label = typeof option === 'string' ? capitalizeWithUnderscore(option) : capitalize(option.label); const value = typeof option === 'string' ? option : option.value; + const isModelSupported = !isProdEnv || supportedModels?.includes(value); return { label, value, + isDisabled: !isModelSupported, }; }), placeholder: placeholder || 'Select an option', @@ -60,6 +64,13 @@ const DropdownComponent: React.FC = ({ {children}
        + {/* {isProdEnv && ( + {LLMDropdownLabel.disabledModels} + + {LLMDropdownLabel.devEnv} + + {'.'} + )} */} ); }; diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index 0043dc241..112f8bbec 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -306,3 +306,8 @@ export const appLabels = { ownSchema: 'Or Define your own Schema', predefinedSchema: 'Select a Pre-defined Schema', }; + +export const LLMDropdownLabel ={ + disabledModels: 'Disabled models are available in the development version. Access more models in our ', + devEnv: 'development environment' +} From 4bed3521cb50478ea4637ed33522d49bc8db5196 Mon Sep 17 00:00:00 2001 From: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Date: Fri, 25 Oct 2024 08:44:58 +0000 Subject: [PATCH 213/292] Exclude session lable node from duplicate nodes list --- backend/src/graphDB_dataAccess.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphDB_dataAccess.py b/backend/src/graphDB_dataAccess.py index 189d581a6..58834eb92 100644 --- a/backend/src/graphDB_dataAccess.py +++ b/backend/src/graphDB_dataAccess.py @@ -354,7 +354,7 @@ def get_duplicate_nodes_list(self): score_value = float(os.environ.get('DUPLICATE_SCORE_VALUE')) text_distance = int(os.environ.get('DUPLICATE_TEXT_DISTANCE')) query_duplicate_nodes = """ - MATCH (n:!Chunk&!Document&!`__Community__`) with n + MATCH (n:!Chunk&!Session&!Document&!`__Community__`) with n WHERE n.embedding is not null and n.id is not null // and size(toString(n.id)) > 3 WITH n ORDER BY count {{ (n)--() }} DESC, size(toString(n.id)) DESC // updated WITH collect(n) as nodes From 3dfb42be3f9fdbb1d47b79733aad02c6c6aee751 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Fri, 25 Oct 2024 15:08:56 +0530 Subject: [PATCH 214/292] Added the tooltip for disabled llm option (#835) --- .../src/components/ChatBot/ChatInfoModal.tsx | 7 +- .../src/components/ChatBot/ChatModeToggle.tsx | 4 +- .../components/ChatBot/ChatModesSwitch.tsx | 4 +- frontend/src/components/ChatBot/ChunkInfo.tsx | 35 ++++--- frontend/src/components/Content.tsx | 30 +++--- .../components/DataSources/AWS/S3Modal.tsx | 4 +- .../components/DataSources/GCS/GCSModal.tsx | 4 +- frontend/src/components/Dropdown.tsx | 94 +++++++++---------- frontend/src/components/FileTable.tsx | 2 +- .../Deduplication/index.tsx | 4 +- .../EntityExtractionSetting.tsx | 10 +- .../SelectedJobList.tsx | 10 +- frontend/src/hooks/useSourceInput.tsx | 4 +- frontend/src/utils/Constants.ts | 13 ++- 14 files changed, 120 insertions(+), 105 deletions(-) diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index 4ffdd9acd..b3c47b4be 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -261,7 +261,12 @@ const ChatInfoModal: React.FC = ({ To generate this response, the process took {response_time} seconds, utilizing {total_tokens} tokens with the model{' '} {model} in{' '} - {chatModeReadableLables[mode] !== 'vector' ? chatModeReadableLables[mode].replace(/\+/g, ' & ') : chatModeReadableLables[mode]} mode. + + {chatModeReadableLables[mode] !== 'vector' + ? chatModeReadableLables[mode].replace(/\+/g, ' & ') + : chatModeReadableLables[mode]} + {' '} + mode. diff --git a/frontend/src/components/ChatBot/ChatModeToggle.tsx b/frontend/src/components/ChatBot/ChatModeToggle.tsx index 52df01a4a..e26da232c 100644 --- a/frontend/src/components/ChatBot/ChatModeToggle.tsx +++ b/frontend/src/components/ChatBot/ChatModeToggle.tsx @@ -38,8 +38,8 @@ export default function ChatModeToggle({ ) ); } - if (!(chatModes.includes(chatModeLables.vector) || chatModes.includes(chatModeLables['graph+vector']))) { - setchatModes([chatModeLables['graph+vector']]); + if (!chatModes.includes(chatModeLables.vector)) { + setchatModes([chatModeLables.vector]); } } }, [selectedRows.length, chatModes.length]); diff --git a/frontend/src/components/ChatBot/ChatModesSwitch.tsx b/frontend/src/components/ChatBot/ChatModesSwitch.tsx index db91e3372..4ace49af5 100644 --- a/frontend/src/components/ChatBot/ChatModesSwitch.tsx +++ b/frontend/src/components/ChatBot/ChatModesSwitch.tsx @@ -17,7 +17,9 @@ export default function ChatModesSwitch({ currentMode: string; isFullScreen: boolean; }) { - const chatmodetoshow =chatModeReadableLables[currentMode].includes('+') ? capitalizeWithPlus(chatModeReadableLables[currentMode]) : capitalize(chatModeReadableLables[currentMode]); + const chatmodetoshow = chatModeReadableLables[currentMode].includes('+') + ? capitalizeWithPlus(chatModeReadableLables[currentMode]) + : capitalize(chatModeReadableLables[currentMode]); return ( = ({ loading, chunks, mode }) => { label='Graph view' className={`${loadingGraphView ? 'cursor-wait' : 'cursor-pointer'}`} onClick={() => handleChunkClick(chunk.element_id, 'Chunk')} - >{'View Graph'} + > + {'View Graph'}
    @@ -98,11 +99,12 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { Similarity Score: {chunk?.score}
    handleChunkClick(chunk.element_id, 'Chunk')} - >{'View Graph'} + > + {'View Graph'}
    @@ -121,10 +123,11 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { Similarity Score: {chunk?.score}
    handleChunkClick(chunk.element_id, 'Chunk')} - >{'View Graph'} + > + {'View Graph'}
    @@ -143,10 +146,11 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { Similarity Score: {chunk?.score}
    handleChunkClick(chunk.element_id, 'Chunk')} - >{'View Graph'} + > + {'View Graph'}
    @@ -165,10 +169,11 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { Similarity Score: {chunk?.score}
    handleChunkClick(chunk.element_id, 'Chunk')} - >{'View Graph'} + > + {'View Graph'}
    @@ -191,10 +196,11 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { Similarity Score: {chunk?.score}
    handleChunkClick(chunk.element_id, 'Chunk')} - >{'View Graph'} + > + {'View Graph'}
    @@ -222,10 +228,11 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => {
    handleChunkClick(chunk.element_id, 'Chunk')} - >{'View Graph'} + > + {'View Graph'}
    diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 83c2c20b4..28caddc1c 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -522,8 +522,9 @@ const Content: React.FC = ({ const handleOpenGraphClick = () => { const bloomUrl = process.env.VITE_BLOOM_URL; const uriCoded = userCredentials?.uri.replace(/:\d+$/, ''); - const connectURL = `${uriCoded?.split('//')[0]}//${userCredentials?.userName}@${uriCoded?.split('//')[1]}:${userCredentials?.port ?? '7687' - }`; + const connectURL = `${uriCoded?.split('//')[0]}//${userCredentials?.userName}@${uriCoded?.split('//')[1]}:${ + userCredentials?.port ?? '7687' + }`; const encodedURL = encodeURIComponent(connectURL); const replacedUrl = bloomUrl?.replace('{CONNECT_URL}', encodedURL); window.open(replacedUrl, '_blank'); @@ -533,10 +534,10 @@ const Content: React.FC = ({ isLeftExpanded && isRightExpanded ? 'contentWithExpansion' : isRightExpanded - ? 'contentWithChatBot' - : !isLeftExpanded && !isRightExpanded - ? 'w-[calc(100%-128px)]' - : 'contentWithDropzoneExpansion'; + ? 'contentWithChatBot' + : !isLeftExpanded && !isRightExpanded + ? 'w-[calc(100%-128px)]' + : 'contentWithDropzoneExpansion'; const handleGraphView = () => { setOpenGraphView(true); @@ -568,12 +569,12 @@ const Content: React.FC = ({ return prev.map((f) => { return f.name === filename ? { - ...f, - status: 'Reprocess', - processingProgress: isStartFromBegining ? 0 : f.processingProgress, - nodesCount: isStartFromBegining ? 0 : f.nodesCount, - relationshipCount: isStartFromBegining ? 0 : f.relationshipsCount, - } + ...f, + status: 'Reprocess', + processingProgress: isStartFromBegining ? 0 : f.processingProgress, + nodesCount: isStartFromBegining ? 0 : f.nodesCount, + relationshipCount: isStartFromBegining ? 0 : f.relationshipsCount, + } : f; }); }); @@ -862,8 +863,9 @@ const Content: React.FC = ({ handleGenerateGraph={processWaitingFilesOnRefresh} > diff --git a/frontend/src/components/DataSources/AWS/S3Modal.tsx b/frontend/src/components/DataSources/AWS/S3Modal.tsx index 8e809dfff..c23b94a3b 100644 --- a/frontend/src/components/DataSources/AWS/S3Modal.tsx +++ b/frontend/src/components/DataSources/AWS/S3Modal.tsx @@ -82,7 +82,7 @@ const S3Modal: React.FC = ({ hideModal, open }) => { name: item.fileName, size: item.fileSize, sourceUrl: item.url, - uploadProgress:100, + uploadProgress: 100, // total_pages: 'N/A', id: uuidv4(), ...defaultValues, @@ -99,7 +99,7 @@ const S3Modal: React.FC = ({ hideModal, open }) => { model: defaultValues.model, fileSource: defaultValues.fileSource, processingProgress: defaultValues.processingProgress, - uploadProgress:100, + uploadProgress: 100, }); } }); diff --git a/frontend/src/components/DataSources/GCS/GCSModal.tsx b/frontend/src/components/DataSources/GCS/GCSModal.tsx index 01b405cee..a68faeb97 100644 --- a/frontend/src/components/DataSources/GCS/GCSModal.tsx +++ b/frontend/src/components/DataSources/GCS/GCSModal.tsx @@ -105,7 +105,7 @@ const GCSModal: React.FC = ({ hideModal, open, openGCSModal }) => id: uuidv4(), accessToken: codeResponse.access_token, ...defaultValues, - uploadProgress:100 + uploadProgress: 100, }); } else { const tempFileData = copiedFilesData[filedataIndex]; @@ -120,7 +120,7 @@ const GCSModal: React.FC = ({ hideModal, open, openGCSModal }) => fileSource: defaultValues.fileSource, processingProgress: defaultValues.processingProgress, accessToken: codeResponse.access_token, - uploadProgress:100 + uploadProgress: 100, }); } } diff --git a/frontend/src/components/Dropdown.tsx b/frontend/src/components/Dropdown.tsx index 8c434309f..663861cfd 100644 --- a/frontend/src/components/Dropdown.tsx +++ b/frontend/src/components/Dropdown.tsx @@ -1,8 +1,9 @@ -import { Dropdown, Tip } from '@neo4j-ndl/react'; +import { Dropdown, Tip, useMediaQuery } from '@neo4j-ndl/react'; import { OptionType, ReusableDropdownProps } from '../types'; -import { memo, useMemo, useReducer } from 'react'; +import { memo, useMemo } from 'react'; import { capitalize, capitalizeWithUnderscore } from '../utils/Utils'; -// import { LLMDropdownLabel } from '../utils/Constants'; +import { prodllms } from '../utils/Constants'; + const DropdownComponent: React.FC = ({ options, placeholder, @@ -13,9 +14,8 @@ const DropdownComponent: React.FC = ({ isDisabled, value, }) => { - const [disableTooltip, toggleDisableState] = useReducer((state) => !state, false); const isProdEnv = process.env.VITE_ENV === 'PROD'; - const supportedModels = process.env.VITE_LLM_MODELS_PROD; + const isLargeDesktop = useMediaQuery(`(min-width:1440px )`); const handleChange = (selectedOption: OptionType | null | void) => { onSelect(selectedOption); }; @@ -23,54 +23,46 @@ const DropdownComponent: React.FC = ({ return ( <>
    - - - { - const label = - typeof option === 'string' ? capitalizeWithUnderscore(option) : capitalize(option.label); - const value = typeof option === 'string' ? option : option.value; - const isModelSupported = !isProdEnv || supportedModels?.includes(value); - return { - label, - value, - isDisabled: !isModelSupported, - }; - }), - placeholder: placeholder || 'Select an option', - defaultValue: defaultValue - ? { label: capitalizeWithUnderscore(defaultValue), value: defaultValue } - : undefined, - menuPlacement: 'auto', - isDisabled: isDisabled, - value: value, - onMenuOpen: () => { - toggleDisableState(); - }, - onMenuClose: () => { - toggleDisableState(); - }, - }} - size='medium' - fluid - /> - - LLM Model used for Extraction & Chat - + LLM Model used for Extraction & Chat
    } + selectProps={{ + onChange: handleChange, + // @ts-ignore + options: allOptions?.map((option) => { + const label = typeof option === 'string' ? capitalizeWithUnderscore(option) : capitalize(option.label); + const value = typeof option === 'string' ? option : option.value; + const isModelSupported = !isProdEnv || prodllms?.includes(value); + return { + label: !isModelSupported ? ( + + + {label} + + Available In Development Version + + ) : ( + {label} + ), + value, + isDisabled: !isModelSupported, + }; + }), + placeholder: placeholder || 'Select an option', + defaultValue: defaultValue + ? { label: capitalizeWithUnderscore(defaultValue), value: defaultValue } + : undefined, + menuPlacement: 'auto', + isDisabled: isDisabled, + value: value, + }} + size='medium' + fluid + /> {children}
    - {/* {isProdEnv && ( - {LLMDropdownLabel.disabledModels} - - {LLMDropdownLabel.devEnv} - - {'.'} - )} */} ); }; diff --git a/frontend/src/components/FileTable.tsx b/frontend/src/components/FileTable.tsx index b3fbafd55..ec367b100 100644 --- a/frontend/src/components/FileTable.tsx +++ b/frontend/src/components/FileTable.tsx @@ -522,7 +522,7 @@ const FileTable = forwardRef((props, ref) => { disabled={info.getValue() === 'Uploading'} clean onClick={() => { - const copied={...info.row.original}; + const copied = { ...info.row.original }; delete copied.accessToken; handleCopy(copied); }} diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx index 1e6b0c213..7140bb6b2 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx @@ -56,8 +56,8 @@ export default function DeduplicationTab() { } if (duplicateNodesData.data.data.length) { setDuplicateNodes(duplicateNodesData.data.data); - //@ts-ignore - setNodesCount(duplicateNodesData.data.message.total) + // @ts-ignore + setNodesCount(duplicateNodesData.data.message.total); } else { setDuplicateNodes([]); } diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/EnitityExtraction/EntityExtractionSetting.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/EnitityExtraction/EntityExtractionSetting.tsx index 67dd10f9e..3ab5b48bd 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/EnitityExtraction/EntityExtractionSetting.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/EnitityExtraction/EntityExtractionSetting.tsx @@ -317,8 +317,9 @@ export default function EntityExtractionSetting({ options: nodeLabelOptions, onChange: onChangenodes, value: selectedNodes, - classNamePrefix: `${isTablet ? 'tablet_entity_extraction_Tab_node_label' : 'entity_extraction_Tab_node_label' - }`, + classNamePrefix: `${ + isTablet ? 'tablet_entity_extraction_Tab_node_label' : 'entity_extraction_Tab_node_label' + }`, }} type='creatable' /> @@ -332,8 +333,9 @@ export default function EntityExtractionSetting({ options: relationshipTypeOptions, onChange: onChangerels, value: selectedRels, - classNamePrefix: `${isTablet ? 'tablet_entity_extraction_Tab_relationship_label' : 'entity_extraction_Tab_relationship_label' - }`, + classNamePrefix: `${ + isTablet ? 'tablet_entity_extraction_Tab_relationship_label' : 'entity_extraction_Tab_relationship_label' + }`, }} type='creatable' /> diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx index 348c97af2..be608f717 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx @@ -11,11 +11,11 @@ export default function SelectedJobList({ }) { const ongoingPostProcessingTasks = useMemo( () => - (isGdsActive - ? postProcessingTasks.includes('enable_communities') - ? postProcessingTasks - : postProcessingTasks.filter((s) => s != 'enable_communities') - : postProcessingTasks.filter((s) => s != 'enable_communities')), + (isGdsActive + ? postProcessingTasks.includes('enable_communities') + ? postProcessingTasks + : postProcessingTasks.filter((s) => s != 'enable_communities') + : postProcessingTasks.filter((s) => s != 'enable_communities')), [isGdsActive, postProcessingTasks] ); return ( diff --git a/frontend/src/hooks/useSourceInput.tsx b/frontend/src/hooks/useSourceInput.tsx index ee75a8cb4..7965c03b9 100644 --- a/frontend/src/hooks/useSourceInput.tsx +++ b/frontend/src/hooks/useSourceInput.tsx @@ -118,7 +118,7 @@ export default function useSourceInput( sourceUrl: item.url, id: uuidv4(), language: item.language, - uploadProgress:100, + uploadProgress: 100, // total_pages: 1, ...defaultValues, }; @@ -138,7 +138,7 @@ export default function useSourceInput( model: defaultValues.model, fileSource: defaultValues.fileSource, processingProgress: defaultValues.processingProgress, - uploadProgress:100, + uploadProgress: 100, }); } } diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index 112f8bbec..8d9289fd8 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -46,6 +46,11 @@ export const supportedLLmsForRagas = [ 'fireworks_llama_v3_70b', 'bedrock_claude_3_5_sonnet', ]; +export const prodllms = + process.env.VITE_LLM_MODELS_PROD?.trim() != '' + ? (process.env.VITE_LLM_MODELS_PROD?.split(',') as string[]) + : ['openai_gpt_4o', 'openai_gpt_4o_mini', 'diffbot', 'gemini_1.5_flash']; + export const chatModeLables = { vector: 'vector', graph: 'graph', @@ -140,7 +145,7 @@ export const tooltips = { }; export const buttonCaptions = { - exploreGraphWithBloom: 'Explore Graph with Bloom', + exploreGraphWithBloom: 'Explore Graph', showPreviewGraph: 'Preview Graph', deleteFiles: 'Delete Files', generateGraph: 'Generate Graph', @@ -307,7 +312,7 @@ export const appLabels = { predefinedSchema: 'Select a Pre-defined Schema', }; -export const LLMDropdownLabel ={ +export const LLMDropdownLabel = { disabledModels: 'Disabled models are available in the development version. Access more models in our ', - devEnv: 'development environment' -} + devEnv: 'development environment', +}; From 4d795bf920ff93c2881cca135c6965addfe75e17 Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Fri, 25 Oct 2024 09:42:45 +0000 Subject: [PATCH 215/292] node size changes --- frontend/src/components/Graph/GraphViewModal.tsx | 6 ------ frontend/src/components/Graph/ResultOverview.tsx | 6 ------ 2 files changed, 12 deletions(-) diff --git a/frontend/src/components/Graph/GraphViewModal.tsx b/frontend/src/components/Graph/GraphViewModal.tsx index 3dc92a745..4f981aa33 100644 --- a/frontend/src/components/Graph/GraphViewModal.tsx +++ b/frontend/src/components/Graph/GraphViewModal.tsx @@ -228,12 +228,6 @@ const GraphViewModal: React.FunctionComponent = ({ return { ...node, selected: match, - size: - match && viewPoint === graphLabels.showGraphView - ? 100 - : match && viewPoint !== graphLabels.showGraphView - ? 50 - : graphLabels.nodeSize, }; }); // deactivating any active relationships diff --git a/frontend/src/components/Graph/ResultOverview.tsx b/frontend/src/components/Graph/ResultOverview.tsx index 93c6b54e3..85143336f 100644 --- a/frontend/src/components/Graph/ResultOverview.tsx +++ b/frontend/src/components/Graph/ResultOverview.tsx @@ -92,12 +92,6 @@ const ResultOverview: React.FunctionComponent = ({ return { ...node, selected: isActive, - size: - isActive && viewPoint === graphLabels.showGraphView - ? 100 - : isActive && viewPoint !== graphLabels.showGraphView - ? 50 - : graphLabels.nodeSize, }; }); // deactivating any active relationships From 1fac375c0d28d060ae73ea903598a3a11a0a7897 Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Fri, 25 Oct 2024 09:50:12 +0000 Subject: [PATCH 216/292] mode removal of rows check --- .../src/components/ChatBot/ChatModeToggle.tsx | 53 ++++--------------- 1 file changed, 11 insertions(+), 42 deletions(-) diff --git a/frontend/src/components/ChatBot/ChatModeToggle.tsx b/frontend/src/components/ChatBot/ChatModeToggle.tsx index e26da232c..d66bda43f 100644 --- a/frontend/src/components/ChatBot/ChatModeToggle.tsx +++ b/frontend/src/components/ChatBot/ChatModeToggle.tsx @@ -9,7 +9,7 @@ import { useCredentials } from '../../context/UserCredentials'; export default function ChatModeToggle({ menuAnchor, - closeHandler = () => {}, + closeHandler = () => { }, open, anchorPortal = true, disableBackdrop = false, @@ -20,30 +20,14 @@ export default function ChatModeToggle({ anchorPortal?: boolean; disableBackdrop?: boolean; }) { - const { setchatModes, chatModes, postProcessingTasks, selectedRows } = useFileContext(); + const { setchatModes, chatModes, postProcessingTasks } = useFileContext(); const isCommunityAllowed = postProcessingTasks.includes('enable_communities'); const { isGdsActive } = useCredentials(); - useEffect(() => { - // If rows are selected, the mode is valid (either vector or graph+vector) - if (selectedRows.length > 0) { - if ( - chatModes.includes(chatModeLables.graph) || - chatModes.includes(chatModeLables.fulltext) || - chatModes.includes(chatModeLables['global search+vector+fulltext']) - ) { - setchatModes((prev) => - prev.filter( - (m) => ![chatModeLables.graph, chatModeLables.fulltext, chatModeLables['graph+vector+fulltext']].includes(m) - ) - ); - } - if (!chatModes.includes(chatModeLables.vector)) { - setchatModes([chatModeLables.vector]); - } + if (!chatModes.length) { + setchatModes([chatModeLables['graph+vector+fulltext']]); } - }, [selectedRows.length, chatModes.length]); - + }, [chatModes.length]); const memoizedChatModes = useMemo(() => { return isGdsActive && isCommunityAllowed ? AvailableModes @@ -51,14 +35,10 @@ export default function ChatModeToggle({ }, [isGdsActive, isCommunityAllowed]); const menuItems = useMemo(() => { return memoizedChatModes?.map((m) => { - const isDisabled = Boolean( - selectedRows.length && !(m.mode === chatModeLables.vector || m.mode === chatModeLables['graph+vector']) - ); const handleModeChange = () => { - if (isDisabled) { - setchatModes([chatModeLables['graph+vector']]); - } else if (chatModes.includes(m.mode)) { - setchatModes((prev) => prev.filter((i) => i != m.mode)); + if (chatModes.includes(m.mode)) { + if (chatModes.length === 1) return; + setchatModes((prev) => prev.filter((i) => i !== m.mode)); } else { setchatModes((prev) => [...prev, m.mode]); } @@ -78,7 +58,7 @@ export default function ChatModeToggle({
    ), onClick: handleModeChange, - disabledCondition: isDisabled, + disabledCondition: false, description: ( {chatModes.includes(m.mode) && ( @@ -86,22 +66,11 @@ export default function ChatModeToggle({ {chatModeLables.selected} )} - {isDisabled && ( - <> - {chatModeLables.unavailableChatMode} - - )} ), }; }); - }, [chatModes.length, memoizedChatModes, closeHandler, selectedRows]); - - useEffect(() => { - if (!selectedRows.length && !chatModes.length) { - setchatModes([]); - } - }, [selectedRows.length, chatModes.length]); + }, [chatModes, memoizedChatModes, closeHandler]); return ( ); -} +} \ No newline at end of file From eb14fbebb8ac9a9d281a9a720072490446a3e6ee Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Fri, 25 Oct 2024 09:56:41 +0000 Subject: [PATCH 217/292] formatting --- frontend/src/components/ChatBot/ChatModeToggle.tsx | 8 +++++--- frontend/src/components/Graph/GraphViewModal.tsx | 1 - frontend/src/components/Graph/ResultOverview.tsx | 2 -- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/ChatBot/ChatModeToggle.tsx b/frontend/src/components/ChatBot/ChatModeToggle.tsx index d66bda43f..0a9a81e10 100644 --- a/frontend/src/components/ChatBot/ChatModeToggle.tsx +++ b/frontend/src/components/ChatBot/ChatModeToggle.tsx @@ -9,7 +9,7 @@ import { useCredentials } from '../../context/UserCredentials'; export default function ChatModeToggle({ menuAnchor, - closeHandler = () => { }, + closeHandler = () => {}, open, anchorPortal = true, disableBackdrop = false, @@ -37,7 +37,9 @@ export default function ChatModeToggle({ return memoizedChatModes?.map((m) => { const handleModeChange = () => { if (chatModes.includes(m.mode)) { - if (chatModes.length === 1) return; + if (chatModes.length === 1) { + return; + } setchatModes((prev) => prev.filter((i) => i !== m.mode)); } else { setchatModes((prev) => [...prev, m.mode]); @@ -81,4 +83,4 @@ export default function ChatModeToggle({ items={menuItems} /> ); -} \ No newline at end of file +} diff --git a/frontend/src/components/Graph/GraphViewModal.tsx b/frontend/src/components/Graph/GraphViewModal.tsx index 4f981aa33..e50f215d1 100644 --- a/frontend/src/components/Graph/GraphViewModal.tsx +++ b/frontend/src/components/Graph/GraphViewModal.tsx @@ -433,7 +433,6 @@ const GraphViewModal: React.FunctionComponent = ({ newScheme={newScheme} searchQuery={searchQuery} setSearchQuery={setSearchQuery} - viewPoint={viewPoint} setNodes={setNodes} setRelationships={setRelationships} /> diff --git a/frontend/src/components/Graph/ResultOverview.tsx b/frontend/src/components/Graph/ResultOverview.tsx index 85143336f..142c9fabc 100644 --- a/frontend/src/components/Graph/ResultOverview.tsx +++ b/frontend/src/components/Graph/ResultOverview.tsx @@ -14,7 +14,6 @@ interface OverViewProps { newScheme: Scheme; searchQuery: string; setSearchQuery: Dispatch>; - viewPoint: string; setNodes: Dispatch>; setRelationships: Dispatch>; } @@ -24,7 +23,6 @@ const ResultOverview: React.FunctionComponent = ({ newScheme, searchQuery, setSearchQuery, - viewPoint, setNodes, setRelationships, }) => { From 5cd9724b42874cd35adc1191ff21fb58ec46b285 Mon Sep 17 00:00:00 2001 From: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Date: Fri, 25 Oct 2024 11:26:58 +0000 Subject: [PATCH 218/292] Exclude __Entity__ node label from duplicate node list --- backend/src/graphDB_dataAccess.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphDB_dataAccess.py b/backend/src/graphDB_dataAccess.py index 58834eb92..82391d1e4 100644 --- a/backend/src/graphDB_dataAccess.py +++ b/backend/src/graphDB_dataAccess.py @@ -354,7 +354,7 @@ def get_duplicate_nodes_list(self): score_value = float(os.environ.get('DUPLICATE_SCORE_VALUE')) text_distance = int(os.environ.get('DUPLICATE_TEXT_DISTANCE')) query_duplicate_nodes = """ - MATCH (n:!Chunk&!Session&!Document&!`__Community__`) with n + MATCH (n:!Chunk&!Session&!Document&!`__Community__`&!`__Entity__`) with n WHERE n.embedding is not null and n.id is not null // and size(toString(n.id)) > 3 WITH n ORDER BY count {{ (n)--() }} DESC, size(toString(n.id)) DESC // updated WITH collect(n) as nodes From 70cb0042fa94e08ab6d88fd54cfbbd6b0fc71aef Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Mon, 28 Oct 2024 14:51:27 +0530 Subject: [PATCH 219/292] Update README.md --- README.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8d05f10fa..79008efdf 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,11 @@ If you are using Neo4j Desktop, you will not be able to use the docker-compose b ### Local deployment #### Running through docker-compose By default only OpenAI and Diffbot are enabled since Gemini requires extra GCP configurations. +Accoroding to enviornment we are configuring the models which is indicated by VITE_LLM_MODELS_PROD variable we can configure model based on our need. +EX: +```env +VITE_LLM_MODELS_PROD="openai_gpt_4o,openai_gpt_4o_mini,diffbot,gemini_1.5_flash" +``` In your root folder, create a .env file with your OPENAI and DIFFBOT keys (if you want to use both): ```env @@ -72,7 +77,7 @@ You can of course combine all (local, youtube, wikipedia, s3 and gcs) or remove ### Chat Modes -By default,all of the chat modes will be available: vector, graph+vector and graph. +By default,all of the chat modes will be available: vector, graph_vector, graph, fulltext, graph_vector_fulltext , entity_vector and global_vector. If none of the mode is mentioned in the chat modes variable all modes will be available: ```env VITE_CHAT_MODES="" @@ -80,7 +85,7 @@ VITE_CHAT_MODES="" If however you want to specify the only vector mode or only graph mode you can do that by specifying the mode in the env: ```env -VITE_CHAT_MODES="vector,graph+vector" +VITE_CHAT_MODES="vector,graph" ``` #### Running Backend and Frontend separately (dev environment) @@ -150,12 +155,14 @@ Allow unauthenticated request : Yes | VITE_TIME_PER_PAGE | Optional | 50 | Time per page for processing | | VITE_CHUNK_SIZE | Optional | 5242880 | Size of each chunk of file for upload | | VITE_GOOGLE_CLIENT_ID | Optional | | Client ID for Google authentication | +| VITE_LLM_MODELS_PROD | Optional | openai_gpt_4o,openai_gpt_4o_mini,diffbot,gemini_1.5_flash | To Distinguish models based on the Enviornment PROD or DEV | GCS_FILE_CACHE | Optional | False | If set to True, will save the files to process into GCS. If set to False, will save the files locally | | ENTITY_EMBEDDING | Optional | False | If set to True, It will add embeddings for each entity in database | | LLM_MODEL_CONFIG_ollama_ | Optional | | Set ollama config as - model_name,model_local_url for local deployments | | RAGAS_EMBEDDING_MODEL | Optional | openai | embedding model used by ragas evaluation framework | + ## For local llms (Ollama) 1. Pull the docker imgage of ollama ```bash From bf51e7883e251b67514ff75853bd82ad30a62a4a Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Tue, 29 Oct 2024 11:09:02 +0530 Subject: [PATCH 220/292] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 79008efdf..64e8c818e 100644 --- a/README.md +++ b/README.md @@ -45,13 +45,13 @@ DIFFBOT_API_KEY="your-diffbot-key" if you only want OpenAI: ```env -VITE_LLM_MODELS="diffbot,openai-gpt-3.5,openai-gpt-4o" +VITE_LLM_MODELS_PROD="diffbot,openai-gpt-3.5,openai-gpt-4o" OPENAI_API_KEY="your-openai-key" ``` if you only want Diffbot: ```env -VITE_LLM_MODELS="diffbot" +VITE_LLM_MODELS_PROD="diffbot" DIFFBOT_API_KEY="your-diffbot-key" ``` From 76b325ca8d570da022c8e0b5f3106aead52586da Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Tue, 29 Oct 2024 11:09:32 +0530 Subject: [PATCH 221/292] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 64e8c818e..fadf6eee9 100644 --- a/README.md +++ b/README.md @@ -149,7 +149,6 @@ Allow unauthenticated request : Yes | VITE_BACKEND_API_URL | Optional | http://localhost:8000 | URL for backend API | | VITE_BLOOM_URL | Optional | https://workspace-preview.neo4j.io/workspace/explore?connectURL={CONNECT_URL}&search=Show+me+a+graph&featureGenAISuggestions=true&featureGenAISuggestionsInternal=true | URL for Bloom visualization | | VITE_REACT_APP_SOURCES | Mandatory | local,youtube,wiki,s3 | List of input sources that will be available | -| VITE_LLM_MODELS | Mandatory | diffbot,openai-gpt-3.5,openai-gpt-4o | Models available for selection on the frontend, used for entities extraction and Q&A | VITE_CHAT_MODES | Mandatory | vector,graph+vector,graph,hybrid | Chat modes available for Q&A | VITE_ENV | Mandatory | DEV or PROD | Environment variable for the app | | VITE_TIME_PER_PAGE | Optional | 50 | Time per page for processing | From 1d607bc6f841459af3ac0f4b6e6093e6cc513cbd Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Wed, 30 Oct 2024 11:59:24 +0000 Subject: [PATCH 222/292] fixed the youtube link --- frontend/src/components/ChatBot/SourcesInfo.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/ChatBot/SourcesInfo.tsx b/frontend/src/components/ChatBot/SourcesInfo.tsx index a934913d9..ddfe92a6e 100644 --- a/frontend/src/components/ChatBot/SourcesInfo.tsx +++ b/frontend/src/components/ChatBot/SourcesInfo.tsx @@ -106,7 +106,7 @@ const SourcesInfo: FC = ({ loading, mode, chunks, sources }) => { )} {!link?.startsWith('s3://') && - !isAllowedHost(link, ['storage.googleapis.com', 'wikipedia.org', 'youtube.com']) && ( + !isAllowedHost(link, ['storage.googleapis.com', 'wikipedia.org', 'www.youtube.com']) && (
    From d8af5a501bfd0203979a40027a8a53b9094e0763 Mon Sep 17 00:00:00 2001 From: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Date: Fri, 8 Nov 2024 11:28:55 +0530 Subject: [PATCH 223/292] Security header and GZIPMiddleware (#847) * Added security header all API * Add GZipMiddleware --- backend/score.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/backend/score.py b/backend/score.py index f7b8c4082..af8400dd5 100644 --- a/backend/score.py +++ b/backend/score.py @@ -33,7 +33,7 @@ from Secweb.ContentSecurityPolicy import ContentSecurityPolicy from Secweb.XContentTypeOptions import XContentTypeOptions from Secweb.XFrameOptions import XFrame - +from fastapi.middleware.gzip import GZipMiddleware from src.ragas_eval import * logger = CustomLogger() @@ -52,10 +52,10 @@ def sick(): app = FastAPI() # SecWeb(app=app, Option={'referrer': False, 'xframe': False}) -# app.add_middleware(HSTS, Option={'max-age': 4}) -# app.add_middleware(ContentSecurityPolicy, Option={'default-src': ["'self'"], 'base-uri': ["'self'"], 'block-all-mixed-content': []}, script_nonce=False, style_nonce=False, report_only=False) -# app.add_middleware(XContentTypeOptions) -# app.add_middleware(XFrame, Option={'X-Frame-Options': 'DENY'}) +app.add_middleware(ContentSecurityPolicy, Option={'default-src': ["'self'"], 'base-uri': ["'self'"], 'block-all-mixed-content': []}, script_nonce=False, style_nonce=False, report_only=False) +app.add_middleware(XContentTypeOptions) +app.add_middleware(XFrame, Option={'X-Frame-Options': 'DENY'}) +app.add_middleware(GZipMiddleware, minimum_size=1000, compresslevel=5) app.add_middleware( CORSMiddleware, From 358d5a6102303b81518965ad6d96053945846515 Mon Sep 17 00:00:00 2001 From: kaustubh-darekar Date: Fri, 8 Nov 2024 11:57:13 +0530 Subject: [PATCH 224/292] Chunk Text Details (#850) * Community title added * Added api for fetching chunk text details * output format changed for chunk text * integrated the service layer for chunkdata * added the chunks * formatting output of llm call for title generation * formatting llm output for title generation * added flex row * Changes related to pagination of fetch chunk api * Integrated the pagination * page changes error resolved for fetch chunk api * for get neighbours api , community title added in properties * moving community title related changes to separate branch * Removed Query module from fastapi import statement * icon changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> --- backend/score.py | 54 +++++++++++++- backend/src/communities.py | 1 - backend/src/graph_query.py | 33 ++++++++- backend/src/shared/constants.py | 13 ++++ frontend/src/components/Content.tsx | 62 ++++++++++++++-- frontend/src/components/FileTable.tsx | 22 +++++- .../components/Popups/ChunkPopUp/index.tsx | 72 +++++++++++++++++++ frontend/src/services/getChunkText.ts | 19 +++++ frontend/src/types.ts | 17 ++++- 9 files changed, 281 insertions(+), 12 deletions(-) create mode 100644 frontend/src/components/Popups/ChunkPopUp/index.tsx create mode 100644 frontend/src/services/getChunkText.ts diff --git a/backend/score.py b/backend/score.py index af8400dd5..93a8c55fa 100644 --- a/backend/score.py +++ b/backend/score.py @@ -12,7 +12,7 @@ from langchain_google_vertexai import ChatVertexAI from src.api_response import create_api_response from src.graphDB_dataAccess import graphDBdataAccess -from src.graph_query import get_graph_results +from src.graph_query import get_graph_results,get_chunktext_results from src.chunkid_entities import get_entities_from_chunkids from src.post_processing import create_vector_fulltext_indexes, create_entity_embedding from sse_starlette.sse import EventSourceResponse @@ -818,5 +818,57 @@ async def calculate_metric(question: str = Form(), finally: gc.collect() +@app.post("/fetch_chunktext") +async def fetch_chunktext( + uri: str = Form(), + database: str = Form(), + userName: str = Form(), + password: str = Form(), + document_name: str = Form(), + page_no: int = Form(1) +): + try: + payload_json_obj = { + 'api_name': 'fetch_chunktext', + 'db_url': uri, + 'userName': userName, + 'database': database, + 'document_name': document_name, + 'page_no': page_no, + 'logging_time': formatted_time(datetime.now(timezone.utc)) + } + logger.log_struct(payload_json_obj, "INFO") + start = time.time() + result = await asyncio.to_thread( + get_chunktext_results, + uri=uri, + username=userName, + password=password, + database=database, + document_name=document_name, + page_no=page_no + ) + end = time.time() + elapsed_time = end - start + json_obj = { + 'api_name': 'fetch_chunktext', + 'db_url': uri, + 'document_name': document_name, + 'page_no': page_no, + 'logging_time': formatted_time(datetime.now(timezone.utc)), + 'elapsed_api_time': f'{elapsed_time:.2f}' + } + logger.log_struct(json_obj, "INFO") + return create_api_response('Success', data=result, message=f"Total elapsed API time {elapsed_time:.2f}") + except Exception as e: + job_status = "Failed" + message = "Unable to get chunk text response" + error_message = str(e) + logging.exception(f'Exception in fetch_chunktext: {error_message}') + return create_api_response(job_status, message=message, error=error_message) + finally: + gc.collect() + + if __name__ == "__main__": uvicorn.run(app) diff --git a/backend/src/communities.py b/backend/src/communities.py index d1130150c..ac0813d8d 100644 --- a/backend/src/communities.py +++ b/backend/src/communities.py @@ -487,4 +487,3 @@ def create_communities(uri, username, password, database,model=COMMUNITY_CREATIO - diff --git a/backend/src/graph_query.py b/backend/src/graph_query.py index fb7333b48..86739ba6c 100644 --- a/backend/src/graph_query.py +++ b/backend/src/graph_query.py @@ -3,7 +3,7 @@ from neo4j import GraphDatabase import os import json -from src.shared.constants import GRAPH_CHUNK_LIMIT,GRAPH_QUERY +from src.shared.constants import GRAPH_CHUNK_LIMIT,GRAPH_QUERY,CHUNK_TEXT_QUERY,COUNT_CHUNKS_QUERY # from neo4j.debug import watch # watch("neo4j") @@ -226,3 +226,34 @@ def get_graph_results(uri, username, password,database,document_names): driver.close() +def get_chunktext_results(uri, username, password, database, document_name, page_no): + """Retrieves chunk text, position, and page number from graph data with pagination.""" + try: + logging.info("Starting chunk text query process") + offset = 10 + skip = (page_no - 1) * offset + limit = offset + driver = GraphDatabase.driver(uri, auth=(username, password)) + with driver.session(database=database) as session: + total_chunks_result = session.run(COUNT_CHUNKS_QUERY, file_name=document_name) + total_chunks = total_chunks_result.single()["total_chunks"] + total_pages = (total_chunks + offset - 1) // offset # Calculate total pages + records = session.run(CHUNK_TEXT_QUERY, file_name=document_name, skip=skip, limit=limit) + pageitems = [ + { + "text": record["chunk_text"], + "position": record["chunk_position"], + "pagenumber": record["page_number"] + } + for record in records + ] + logging.info(f"Query process completed with {len(pageitems)} chunks retrieved") + return { + "pageitems": pageitems, + "total_pages": total_pages + } + except Exception as e: + logging.error(f"An error occurred in get_chunktext_results. Error: {str(e)}") + raise Exception("An error occurred in get_chunktext_results. Please check the logs for more details.") from e + finally: + driver.close() \ No newline at end of file diff --git a/backend/src/shared/constants.py b/backend/src/shared/constants.py index b58fd3a67..83cb69245 100644 --- a/backend/src/shared/constants.py +++ b/backend/src/shared/constants.py @@ -161,6 +161,19 @@ ] AS entities """ +COUNT_CHUNKS_QUERY = """ +MATCH (d:Document {fileName: $file_name})<-[:PART_OF]-(c:Chunk) +RETURN count(c) AS total_chunks +""" + +CHUNK_TEXT_QUERY = """ +MATCH (d:Document {fileName: $file_name})<-[:PART_OF]-(c:Chunk) +RETURN c.text AS chunk_text, c.position AS chunk_position, c.page_number AS page_number +ORDER BY c.position +SKIP $skip +LIMIT $limit +""" + ## CHAT SETUP CHAT_MAX_TOKENS = 1000 CHAT_SEARCH_KWARG_SCORE_THRESHOLD = 0.5 diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 28caddc1c..cab5a2673 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -11,6 +11,7 @@ import { CustomFile, OptionType, UserCredentials, + chunkdata, connectionState, } from '../types'; import deleteAPI from '../services/DeleteFiles'; @@ -44,6 +45,8 @@ import retry from '../services/retry'; import { showErrorToast, showNormalToast, showSuccessToast } from '../utils/toasts'; import { useMessageContext } from '../context/UserMessages'; import PostProcessingToast from './Popups/GraphEnhancementDialog/PostProcessingCheckList/PostProcessingToast'; +import { getChunkText } from '../services/getChunkText'; +import ChunkPopUp from './Popups/ChunkPopUp'; const ConnectionModal = lazy(() => import('./Popups/ConnectionModal/ConnectionModal')); const ConfirmationDialog = lazy(() => import('./Popups/LargeFilePopUp/ConfirmationDialog')); @@ -70,6 +73,7 @@ const Content: React.FC = ({ }); const [openGraphView, setOpenGraphView] = useState(false); const [inspectedName, setInspectedName] = useState(''); + const [documentName, setDocumentName] = useState(''); const { setUserCredentials, userCredentials, @@ -85,6 +89,12 @@ const Content: React.FC = ({ const [retryFile, setRetryFile] = useState(''); const [retryLoading, setRetryLoading] = useState(false); const [showRetryPopup, toggleRetryPopup] = useReducer((state) => !state, false); + const [showChunkPopup, toggleChunkPopup] = useReducer((state) => !state, false); + const [chunksLoading, toggleChunksLoading] = useReducer((state) => !state, false); + const [currentPage, setCurrentPage] = useState(0); + const [totalPageCount, setTotalPageCount] = useState(null); + const [textChunks, setTextChunks] = useState([]); + const [alertStateForRetry, setAlertStateForRetry] = useState({ showAlert: false, alertType: 'neutral', @@ -122,7 +132,12 @@ const Content: React.FC = ({ } ); const childRef = useRef(null); - + const incrementPage = () => { + setCurrentPage((prev) => prev + 1); + }; + const decrementPage = () => { + setCurrentPage((prev) => prev - 1); + }; useEffect(() => { if (!init && !searchParams.has('connectURL')) { let session = localStorage.getItem('neo4j.connection'); @@ -149,7 +164,13 @@ const Content: React.FC = ({ setOpenConnection((prev) => ({ ...prev, openPopUp: true })); } }, []); - + useEffect(() => { + if (currentPage >= 1) { + (async () => { + await getChunks(documentName, currentPage); + })(); + } + }, [currentPage, documentName]); useEffect(() => { setFilesData((prevfiles) => { return prevfiles.map((curfile) => { @@ -251,7 +272,15 @@ const Content: React.FC = ({ setModel(selectedOption?.value); } }; - + const getChunks = async (name: string, pageNo: number) => { + toggleChunksLoading(); + const response = await getChunkText(userCredentials as UserCredentials, name, pageNo); + setTextChunks(response.data.data.pageitems); + if (!totalPageCount) { + setTotalPageCount(response.data.data.total_pages); + } + toggleChunksLoading(); + }; const extractData = async (uid: string, isselectedRows = false, filesTobeProcess: CustomFile[]) => { if (!isselectedRows) { const fileItem = filesData.find((f) => f.id == uid); @@ -497,7 +526,7 @@ const Content: React.FC = ({ } }; - function processWaitingFilesOnRefresh() { + const processWaitingFilesOnRefresh = () => { let data = []; const processingFilesCount = filesData.filter((f) => f.status === 'Processing').length; @@ -517,7 +546,7 @@ const Content: React.FC = ({ .filter((f) => f.status === 'New' || f.status == 'Reprocess'); addFilesToQueue(selectedNewFiles as CustomFile[]); } - } + }; const handleOpenGraphClick = () => { const bloomUrl = process.env.VITE_BLOOM_URL; @@ -771,6 +800,18 @@ const Content: React.FC = ({ view='contentView' > )} + {showChunkPopup && ( + toggleChunkPopup()} + showChunkPopup={showChunkPopup} + chunks={textChunks} + incrementPage={incrementPage} + decrementPage={decrementPage} + currentPage={currentPage} + totalPageCount={totalPageCount} + > + )} {showEnhancementDialog && ( = ({ setRetryFile(id); toggleRetryPopup(); }} + onChunkView={async (name) => { + setDocumentName(name); + if (name != documentName) { + toggleChunkPopup(); + if (totalPageCount) { + setTotalPageCount(null); + } + setCurrentPage(1); + // await getChunks(name, 1); + } + }} ref={childRef} handleGenerateGraph={processWaitingFilesOnRefresh} > diff --git a/frontend/src/components/FileTable.tsx b/frontend/src/components/FileTable.tsx index ec367b100..8cc8d48ed 100644 --- a/frontend/src/components/FileTable.tsx +++ b/frontend/src/components/FileTable.tsx @@ -38,8 +38,9 @@ import { SourceNode, CustomFile, FileTableProps, UserCredentials, statusupdate, import { useCredentials } from '../context/UserCredentials'; import { ArrowPathIconSolid, - ClipboardDocumentIconOutline, + ClipboardDocumentIconSolid, MagnifyingGlassCircleIconSolid, + DocumentTextIconSolid, } from '@neo4j-ndl/react/icons'; import CustomProgressBar from './UI/CustomProgressBar'; import subscribe from '../services/PollingAPI'; @@ -56,7 +57,7 @@ import { ThemeWrapperContext } from '../context/ThemeWrapper'; let onlyfortheFirstRender = true; const FileTable = forwardRef((props, ref) => { - const { isExpanded, connectionStatus, setConnectionStatus, onInspect, onRetry } = props; + const { isExpanded, connectionStatus, setConnectionStatus, onInspect, onRetry, onChunkView } = props; const { filesData, setFilesData, model, rowSelection, setRowSelection, setSelectedRows, setProcessedCount, queue } = useFileContext(); const { userCredentials, isReadOnlyUser } = useCredentials(); @@ -527,10 +528,25 @@ const FileTable = forwardRef((props, ref) => { handleCopy(copied); }} > - + + + { + onChunkView(info?.row?.original?.name as string); + }} + clean + placement='left' + label='chunktextaction' + text='View Chunks' + size='large' + disabled={info.getValue() === 'Uploading'} + > + ), + size: 300, + minSize: 180, header: () => Actions, footer: (info) => info.column.id, }), diff --git a/frontend/src/components/Popups/ChunkPopUp/index.tsx b/frontend/src/components/Popups/ChunkPopUp/index.tsx new file mode 100644 index 000000000..7966ddd6e --- /dev/null +++ b/frontend/src/components/Popups/ChunkPopUp/index.tsx @@ -0,0 +1,72 @@ +import { Dialog, Typography, Flex, IconButton } from '@neo4j-ndl/react'; +import { ArrowLeftIconOutline, ArrowRightIconOutline } from '@neo4j-ndl/react/icons'; +import { chunkdata } from '../../../types'; +import Loader from '../../../utils/Loader'; +import { useMemo } from 'react'; + +const ChunkPopUp = ({ + showChunkPopup, + chunks, + onClose, + chunksLoading, + incrementPage, + decrementPage, + currentPage, + totalPageCount, +}: { + showChunkPopup: boolean; + chunks: chunkdata[]; + onClose: () => void; + chunksLoading: boolean; + incrementPage: () => void; + decrementPage: () => void; + currentPage: number | null; + totalPageCount: number | null; +}) => { + const sortedChunksData = useMemo(() => { + return chunks.sort((a, b) => a.position - b.position); + }, [chunks]); + return ( + + Text Chunks + + {chunksLoading ? ( + + ) : ( +
      + {sortedChunksData.map((c, idx) => ( +
    1. + + + Position : + {c.position} + + {c.pagenumber ? ( + + Page No :{' '} + {c.pagenumber} + + ) : null} + {c.text} + +
    2. + ))} +
    + )} +
    + {totalPageCount != null && totalPageCount > 1 && ( + + + + + + + + + + + )} +
    + ); +}; +export default ChunkPopUp; diff --git a/frontend/src/services/getChunkText.ts b/frontend/src/services/getChunkText.ts new file mode 100644 index 000000000..f9825dc34 --- /dev/null +++ b/frontend/src/services/getChunkText.ts @@ -0,0 +1,19 @@ +import { UserCredentials, chunksData } from '../types'; +import api from '../API/Index'; + +export const getChunkText = async (userCredentials: UserCredentials, documentName: string, page_no: number) => { + const formData = new FormData(); + formData.append('uri', userCredentials?.uri ?? ''); + formData.append('database', userCredentials?.database ?? ''); + formData.append('userName', userCredentials?.userName ?? ''); + formData.append('password', userCredentials?.password ?? ''); + formData.append('document_name', documentName); + formData.append('page_no', page_no.toString()); + try { + const response = await api.post(`/fetch_chunktext`, formData); + return response; + } catch (error) { + console.log(error); + throw error; + } +}; diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 02dbc0a2b..6bc34d2da 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -154,6 +154,7 @@ export interface FileTableProps { connectionStatus: boolean; setConnectionStatus: Dispatch>; onInspect: (id: string) => void; + onChunkView: (name: string) => void; handleGenerateGraph: () => void; onRetry: (id: string) => void; } @@ -379,7 +380,13 @@ export interface commonserverresponse { error?: string; message?: string | orphanTotalNodes; file_name?: string; - data?: labelsAndTypes | labelsAndTypes[] | uploadData | orphanNodeProps[] | dupNodes[]; + data?: + | labelsAndTypes + | labelsAndTypes[] + | uploadData + | orphanNodeProps[] + | dupNodes[] + | { pageitems: chunkdata[]; total_pages: number }; } export interface dupNodeProps { id: string; @@ -397,6 +404,11 @@ export interface selectedDuplicateNodes { firstElementId: string; similarElementIds: string[]; } +export interface chunkdata { + text: string; + position: number; + pagenumber: null | number; +} export interface ScehmaFromText extends Partial { data: labelsAndTypes; } @@ -407,6 +419,9 @@ export interface ServerData extends Partial { export interface duplicateNodesData extends Partial { data: dupNodes[]; } +export interface chunksData extends Partial { + data: { pageitems: chunkdata[]; total_pages: number }; +} export interface OrphanNodeResponse extends Partial { data: orphanNodeProps[]; } From 6d35a34664e52f0d37392ef685466af30b11e844 Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Fri, 8 Nov 2024 14:33:16 +0530 Subject: [PATCH 225/292] Communities Id to Title (#851) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Staging to main (#735) * Dev (#537) * format fixes and graph schema indication fix * Update README.md * added chat modes variable in env updated the readme * spell fix * added the chat mode in env table * added the logos * fixed the overflow issues * removed the extra fix * Fixed specific scenario "when the text from schema closes it should reopen the previous modal" * readme changes * removed dev console logs * added new retrieval query (#533) * format fixes and tab rendering fix * fixed the setting modal reopen issue --------- Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * disabled the sumbit buttom on loading * Deduplication tab (#566) * de-duplication API * Update De-Duplicate query * created the Deduplication tab * added the API service * added the removeable tags for similar nodes in deduplication tab * Integrate Tag * added GraphLabel * added loader state * added the merge service * integrated the merge API * Merge Query issue fixed * Auto refresh the duplicate nodes after merging operation * added the description for de duplication * reset on merging --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Update frontend_docs.adoc (#538) * Update frontend_docs.adoc * doc update * Images * Images folder change * Images folder change * test image * Update frontend_docs.adoc * image change * Update frontend_docs.adoc * Update frontend_docs.adoc * added the Graph Mode SS * added the Query SS * Update frontend_docs.adoc * conflics fix * conflict fix * Update frontend_docs.adoc --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * updated langchain versions (#565) * Update the De-Duplication query * Node relationship id type none issue (#547) * de-duplication API * Update De-Duplicate query * Issue fixed Nodes,Relationship Id and Type None or Blank * added the tooltips * type fix * Unneccory import * added score threshold and added some error handling (#571) * Update requirements.txt * Tooltip and other UI fixes (#572) * Staging To Main (#495) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * Dev (#433) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env * DEV to STAGING (#461) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * DEV to STAGING (#462) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * added upload api * changed the dropzone error message * Dev to staging (#466) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env * added upload api * changed the dropzone error message --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-auth… * Update FileTable.tsx * DEV to STAGING (#833) * updated script"integration test cases" * decreased the delay for pollintg API * Graph enhancements (#696) * relationship Changes * addition of relationship labels * onclick to nodes * node-highlight * Build fixex * slash docker change * deactivating previous node/relationshsips * lint fixes * class issue * search * search on basis of id / captions * debounce changes * class changes (#693) * legends highlight * search query reset * node size * changed chat mode names (#702) * env changes * used axios instance for network calls * disabled the toolip when dropdown is open state * format fixes + chat mode naming changes * mode added to info model for entities * Issue fixed, List out of index while getting status of dicuement node * processing count updated on cancel * format fixes * remove whitespace for enviroment variable which due to an error "xxx may not contain whitespace" (#707) * updated disconnected nodes * updated disconnected nodes * fix: Processed count update on failed condition * added disconnected and up nodes * removed __Entity__ labels * removed graph_object * removed graph object in the function * resetting the alert message on success scenario * Modified queries * populate graph schema * not clearing the password when there is error scenario * fixed the vector index loading issue * fix: empty credentials payload for recreate vector index api * chatbot status (#676) * chatbot status * connection status check for ASK button * refresh disable check * review comment resolved * format fixes * added properties and modified to entity labels * Post processing call after all files completion (#716) * Dev To STAGING (#532) * format fixes and graph schema indication fix * Update README.md * added chat modes variable in env updated the readme * spell fix * added the chat mode in env table * added the logos * fixed the overflow issues * removed the extra fix * Fixed specific scenario "when the text from schema closes it should reopen the previous modal" * readme changes * removed dev console logs * added new retrieval query (#533) * format fixes and tab rendering fix * fixed the setting modal reopen issue --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Dev (#535) * format fixes and graph schema indication fix * Update README.md * added chat modes variable in env updated the readme * spell fix * added the chat mode in env table * added the logos * fixed the overflow issues * removed the extra fix * Fixed specific scenario "when the text from schema closes it should reopen the previous modal" * readme changes * removed dev console logs * added new retrieval query (#533) * format fixes and tab rendering fix * fixed the setting modal reopen issue --------- Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Dev (#537) * format fixes and graph schema indication fix * Update README.md * added chat modes variable in env updated the readme * spell fix * added the chat mode in env table * added the logos * fixed the overflow issues * removed the extra fix * Fixed specific scenario "when the text from schema closes it should reopen the previous modal" * readme changes * removed dev console logs * added new retrieval query (#533) * format fixes and tab rendering fix * fixed the setting modal reopen issue --------- Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Fix typo: correct 'josn_obj' to 'json_obj' (#697) * Staging To Main (#495) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * Dev (#433) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env * DEV to STAGING (#461) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * DEV to STAGING (#462) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * added upload api * changed the dropzone error message * Dev to staging (#466) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload ----… * Dev to STAGING (#836) * updated script"integration test cases" * decreased the delay for pollintg API * Graph enhancements (#696) * relationship Changes * addition of relationship labels * onclick to nodes * node-highlight * Build fixex * slash docker change * deactivating previous node/relationshsips * lint fixes * class issue * search * search on basis of id / captions * debounce changes * class changes (#693) * legends highlight * search query reset * node size * changed chat mode names (#702) * env changes * used axios instance for network calls * disabled the toolip when dropdown is open state * format fixes + chat mode naming changes * mode added to info model for entities * Issue fixed, List out of index while getting status of dicuement node * processing count updated on cancel * format fixes * remove whitespace for enviroment variable which due to an error "xxx may not contain whitespace" (#707) * updated disconnected nodes * updated disconnected nodes * fix: Processed count update on failed condition * added disconnected and up nodes * removed __Entity__ labels * removed graph_object * removed graph object in the function * resetting the alert message on success scenario * Modified queries * populate graph schema * not clearing the password when there is error scenario * fixed the vector index loading issue * fix: empty credentials payload for recreate vector index api * chatbot status (#676) * chatbot status * connection status check for ASK button * refresh disable check * review comment resolved * format fixes * added properties and modified to entity labels * Post processing call after all files completion (#716) * Dev To STAGING (#532) * format fixes and graph schema indication fix * Update README.md * added chat modes variable in env updated the readme * spell fix * added the chat mode in env table * added the logos * fixed the overflow issues * removed the extra fix * Fixed specific scenario "when the text from schema closes it should reopen the previous modal" * readme changes * removed dev console logs * added new retrieval query (#533) * format fixes and tab rendering fix * fixed the setting modal reopen issue --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Dev (#535) * format fixes and graph schema indication fix * Update README.md * added chat modes variable in env updated the readme * spell fix * added the chat mode in env table * added the logos * fixed the overflow issues * removed the extra fix * Fixed specific scenario "when the text from schema closes it should reopen the previous modal" * readme changes * removed dev console logs * added new retrieval query (#533) * format fixes and tab rendering fix * fixed the setting modal reopen issue --------- Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Dev (#537) * format fixes and graph schema indication fix * Update README.md * added chat modes variable in env updated the readme * spell fix * added the chat mode in env table * added the logos * fixed the overflow issues * removed the extra fix * Fixed specific scenario "when the text from schema closes it should reopen the previous modal" * readme changes * removed dev console logs * added new retrieval query (#533) * format fixes and tab rendering fix * fixed the setting modal reopen issue --------- Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Fix typo: correct 'josn_obj' to 'json_obj' (#697) * Staging To Main (#495) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * Dev (#433) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env * DEV to STAGING (#461) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * DEV to STAGING (#462) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * added upload api * changed the dropzone error message * Dev to staging (#466) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload ----… * Dev (#837) * updated script"integration test cases" * decreased the delay for pollintg API * Graph enhancements (#696) * relationship Changes * addition of relationship labels * onclick to nodes * node-highlight * Build fixex * slash docker change * deactivating previous node/relationshsips * lint fixes * class issue * search * search on basis of id / captions * debounce changes * class changes (#693) * legends highlight * search query reset * node size * changed chat mode names (#702) * env changes * used axios instance for network calls * disabled the toolip when dropdown is open state * format fixes + chat mode naming changes * mode added to info model for entities * Issue fixed, List out of index while getting status of dicuement node * processing count updated on cancel * format fixes * remove whitespace for enviroment variable which due to an error "xxx may not contain whitespace" (#707) * updated disconnected nodes * updated disconnected nodes * fix: Processed count update on failed condition * added disconnected and up nodes * removed __Entity__ labels * removed graph_object * removed graph object in the function * resetting the alert message on success scenario * Modified queries * populate graph schema * not clearing the password when there is error scenario * fixed the vector index loading issue * fix: empty credentials payload for recreate vector index api * chatbot status (#676) * chatbot status * connection status check for ASK button * refresh disable check * review comment resolved * format fixes * added properties and modified to entity labels * Post processing call after all files completion (#716) * Dev To STAGING (#532) * format fixes and graph schema indication fix * Update README.md * added chat modes variable in env updated the readme * spell fix * added the chat mode in env table * added the logos * fixed the overflow issues * removed the extra fix * Fixed specific scenario "when the text from schema closes it should reopen the previous modal" * readme changes * removed dev console logs * added new retrieval query (#533) * format fixes and tab rendering fix * fixed the setting modal reopen issue --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Dev (#535) * format fixes and graph schema indication fix * Update README.md * added chat modes variable in env updated the readme * spell fix * added the chat mode in env table * added the logos * fixed the overflow issues * removed the extra fix * Fixed specific scenario "when the text from schema closes it should reopen the previous modal" * readme changes * removed dev console logs * added new retrieval query (#533) * format fixes and tab rendering fix * fixed the setting modal reopen issue --------- Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Dev (#537) * format fixes and graph schema indication fix * Update README.md * added chat modes variable in env updated the readme * spell fix * added the chat mode in env table * added the logos * fixed the overflow issues * removed the extra fix * Fixed specific scenario "when the text from schema closes it should reopen the previous modal" * readme changes * removed dev console logs * added new retrieval query (#533) * format fixes and tab rendering fix * fixed the setting modal reopen issue --------- Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Fix typo: correct 'josn_obj' to 'json_obj' (#697) * Staging To Main (#495) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * Dev (#433) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env * DEV to STAGING (#461) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * DEV to STAGING (#462) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * added upload api * changed the dropzone error message * Dev to staging (#466) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co… * merge changes * Update README.md * Update README.md * removal of extra LLm env * Community name * title generation * removed logging statement added for debugging * env changes --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: Ikko Eltociear Ashimine Co-authored-by: Jayanth T Co-authored-by: Jayanth T Co-authored-by: Jerome Choo Co-authored-by: jeromechoo Co-authored-by: Michael Hunger Co-authored-by: Kain Shu <44948284+Kain-90@users.noreply.github.com> Co-authored-by: destiny966113 <90891243+destiny966113@users.noreply.github.com> Co-authored-by: Pravesh1988 Co-authored-by: edenbuaa Co-authored-by: kaustubh-darekar Co-authored-by: a-s-poorna --- backend/src/communities.py | 48 ++++++--- backend/src/neighbours.py | 3 +- backend/src/shared/constants.py | 2 +- backend/test_integrationqa.py | 21 ++++ docker-compose.yml | 2 +- example.env | 1 - frontend/Dockerfile | 1 - frontend/src/components/ChatBot/ChunkInfo.tsx | 13 +-- .../components/ChatBot/CommunitiesInfo.tsx | 8 +- .../src/components/ChatBot/EntitiesInfo.tsx | 11 +-- frontend/src/components/ChatBot/chatInfo.ts | 15 +-- frontend/src/components/Content.tsx | 5 +- frontend/src/components/FileTable.tsx | 2 +- .../src/components/Graph/GraphViewModal.tsx | 36 +++---- frontend/src/components/Layout/PageLayout.tsx | 1 - .../ConnectionModal/ConnectionModal.tsx | 2 +- .../Deduplication/index.tsx | 5 +- .../DeleteTabForOrphanNodes/index.tsx | 5 +- frontend/src/components/QuickStarter.tsx | 19 ++-- frontend/src/types.ts | 9 ++ frontend/src/utils/Constants.ts | 99 ++++++++++--------- frontend/src/utils/Utils.ts | 3 + 22 files changed, 173 insertions(+), 138 deletions(-) diff --git a/backend/src/communities.py b/backend/src/communities.py index ac0813d8d..a38b39696 100644 --- a/backend/src/communities.py +++ b/backend/src/communities.py @@ -107,24 +107,38 @@ STORE_COMMUNITY_SUMMARIES = """ UNWIND $data AS row MERGE (c:__Community__ {id:row.community}) -SET c.summary = row.summary +SET c.summary = row.summary, + c.title = row.title """ + COMMUNITY_SYSTEM_TEMPLATE = "Given input triples, generate the information summary. No pre-amble." -COMMUNITY_TEMPLATE = """Based on the provided nodes and relationships that belong to the same graph community, -generate a natural language summary of the provided information: -{community_info} -Summary:""" +COMMUNITY_TEMPLATE = """ +Based on the provided nodes and relationships that belong to the same graph community, +generate following output in exact format +title: A concise title, no more than 4 words, +summary: A natural language summary of the information +{community_info} +Example output: +title: Example Title, +summary: This is an example summary that describes the key information of this community. +""" PARENT_COMMUNITY_SYSTEM_TEMPLATE = "Given an input list of community summaries, generate a summary of the information" PARENT_COMMUNITY_TEMPLATE = """Based on the provided list of community summaries that belong to the same graph community, -generate a natural language summary of the information.Include all the necessary information as possible +generate following output in exact format +title: A concise title, no more than 4 words, +summary: A natural language summary of the information. Include all the necessary information as much as possible. + {community_info} -Summary:""" +Example output: +title: Example Title, +summary: This is an example summary that describes the key information of this community. +""" GET_COMMUNITY_DETAILS = """ @@ -277,8 +291,17 @@ def process_community_info(community, chain, is_parent=False): combined_text = " ".join(f"Summary {i+1}: {summary}" for i, summary in enumerate(community.get("texts", []))) else: combined_text = prepare_string(community) - summary = chain.invoke({'community_info': combined_text}) - return {"community": community['communityId'], "summary": summary} + summary_response = chain.invoke({'community_info': combined_text}) + lines = summary_response.splitlines() + title = "Untitled Community" + summary = "" + for line in lines: + if line.lower().startswith("title"): + title = line.split(":", 1)[-1].strip() + elif line.lower().startswith("summary"): + summary = line.split(":", 1)[-1].strip() + logging.info(f"Community Title : {title}") + return {"community": community['communityId'], "title":title, "summary": summary} except Exception as e: logging.error(f"Failed to process community {community.get('communityId', 'unknown')}: {e}") return None @@ -291,7 +314,7 @@ def create_community_summaries(gds, model): summaries = [] with ThreadPoolExecutor() as executor: futures = [executor.submit(process_community_info, community, community_chain) for community in community_info_list.to_dict(orient="records")] - + for future in as_completed(futures): result = future.result() if result: @@ -482,8 +505,3 @@ def create_communities(uri, username, password, database,model=COMMUNITY_CREATIO logging.warning("Failed to write communities. Constraint was not applied.") except Exception as e: logging.error(f"Failed to create communities: {e}") - - - - - diff --git a/backend/src/neighbours.py b/backend/src/neighbours.py index 08022ecc6..431d5b4bd 100644 --- a/backend/src/neighbours.py +++ b/backend/src/neighbours.py @@ -20,7 +20,8 @@ labels: [coalesce(apoc.coll.removeAll(labels(node), ['__Entity__'])[0], "*")], element_id: elementId(node), properties: { - id: CASE WHEN node.id IS NOT NULL THEN node.id ELSE node.fileName END + id: CASE WHEN node.id IS NOT NULL THEN node.id ELSE node.fileName END, + title: CASE WHEN node.title IS NOT NULL THEN node.title ELSE " " END } } ] AS nodes, diff --git a/backend/src/shared/constants.py b/backend/src/shared/constants.py index 83cb69245..084b5d1ba 100644 --- a/backend/src/shared/constants.py +++ b/backend/src/shared/constants.py @@ -730,4 +730,4 @@ value "2023-03-15"." "## 5. Strict Compliance\n" "Adhere to the rules strictly. Non-compliance will result in termination." - """ \ No newline at end of file + """ diff --git a/backend/test_integrationqa.py b/backend/test_integrationqa.py index 548e9706f..ede8077f7 100644 --- a/backend/test_integrationqa.py +++ b/backend/test_integrationqa.py @@ -124,6 +124,27 @@ def test_graph_website(model_name): print("Fail: ", e) return weburl_result +def test_graph_website(model_name): + """Test graph creation from a Website page.""" + #graph, model, source_url, source_type + source_url = 'https://www.amazon.com/' + source_type = 'web-url' + create_source_node_graph_web_url(graph, model_name, source_url, source_type) + + weburl_result = extract_graph_from_web_page(URI, USERNAME, PASSWORD, DATABASE, model_name, source_url, '', '') + logging.info("WebUrl test done") + print(weburl_result) + + try: + assert weburl_result['status'] == 'Completed' + assert weburl_result['nodeCount'] > 0 + assert weburl_result['relationshipCount'] > 0 + print("Success") + except AssertionError as e: + print("Fail: ", e) + return weburl_result + + def test_graph_from_youtube_video(model_name): """Test graph creation from a YouTube video.""" source_url = 'https://www.youtube.com/watch?v=T-qy-zPWgqA' diff --git a/docker-compose.yml b/docker-compose.yml index ea6d2c050..8a0fdc4b2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -53,7 +53,6 @@ services: args: - VITE_BACKEND_API_URL=${VITE_BACKEND_API_URL-http://localhost:8000} - VITE_REACT_APP_SOURCES=${VITE_REACT_APP_SOURCES-local,wiki,s3} - - VITE_LLM_MODELS=${VITE_LLM_MODELS-} - VITE_GOOGLE_CLIENT_ID=${VITE_GOOGLE_CLIENT_ID-} - VITE_BLOOM_URL=${VITE_BLOOM_URL-https://workspace-preview.neo4j.io/workspace/explore?connectURL={CONNECT_URL}&search=Show+me+a+graph&featureGenAISuggestions=true&featureGenAISuggestionsInternal=true} - VITE_TIME_PER_PAGE=${VITE_TIME_PER_PAGE-50} @@ -62,6 +61,7 @@ services: - VITE_ENV=${VITE_ENV-DEV} - VITE_CHAT_MODES=${VITE_CHAT_MODES-} - VITE_BATCH_SIZE=${VITE_BATCH_SIZE-2} + - VITE_LLM_MODELS=${VITE_LLM_MODELS-} - VITE_LLM_MODELS_PROD=${VITE_LLM_MODELS_PROD-openai_gpt_4o,openai_gpt_4o_mini,diffbot,gemini_1.5_flash} volumes: - ./frontend:/app diff --git a/example.env b/example.env index 6b542daf1..5d3a598c9 100644 --- a/example.env +++ b/example.env @@ -24,7 +24,6 @@ ENTITY_EMBEDDING=True VITE_BACKEND_API_URL="http://localhost:8000" VITE_BLOOM_URL="https://workspace-preview.neo4j.io/workspace/explore?connectURL={CONNECT_URL}&search=Show+me+a+graph&featureGenAISuggestions=true&featureGenAISuggestionsInternal=true" VITE_REACT_APP_SOURCES="local,youtube,wiki,s3,web" -VITE_LLM_MODELS="diffbot,openai-gpt-3.5,openai-gpt-4o" # ",ollama_llama3" VITE_ENV="DEV" VITE_TIME_PER_PAGE=50 VITE_CHUNK_SIZE=5242880 diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 3053e1ba9..311294f4a 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -20,7 +20,6 @@ RUN yarn install COPY . ./ RUN VITE_BACKEND_API_URL=$VITE_BACKEND_API_URL \ VITE_REACT_APP_SOURCES=$VITE_REACT_APP_SOURCES \ - VITE_LLM_MODELS=$VITE_LLM_MODELS \ VITE_GOOGLE_CLIENT_ID=$VITE_GOOGLE_CLIENT_ID \ VITE_BLOOM_URL=$VITE_BLOOM_URL \ VITE_CHUNK_SIZE=$VITE_CHUNK_SIZE \ diff --git a/frontend/src/components/ChatBot/ChunkInfo.tsx b/frontend/src/components/ChatBot/ChunkInfo.tsx index 8568e0b5d..aa16d9451 100644 --- a/frontend/src/components/ChatBot/ChunkInfo.tsx +++ b/frontend/src/components/ChatBot/ChunkInfo.tsx @@ -21,18 +21,16 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { const [neoRels, setNeoRels] = useState([]); const [openGraphView, setOpenGraphView] = useState(false); const [viewPoint, setViewPoint] = useState(''); - const [loadingGraphView, setLoadingGraphView] = useState(false); const handleChunkClick = (elementId: string, viewMode: string) => { + setOpenGraphView(true); + setViewPoint('chatInfoView'); handleGraphNodeClick( userCredentials as UserCredentials, elementId, viewMode, setNeoNodes, setNeoRels, - setOpenGraphView, - setViewPoint, - setLoadingGraphView ); }; @@ -72,7 +70,6 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => {
    handleChunkClick(chunk.element_id, 'Chunk')} > {'View Graph'} @@ -100,7 +97,6 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => {
    handleChunkClick(chunk.element_id, 'Chunk')} > @@ -123,7 +119,6 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { Similarity Score: {chunk?.score}
    handleChunkClick(chunk.element_id, 'Chunk')} > @@ -146,7 +141,6 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { Similarity Score: {chunk?.score}
    handleChunkClick(chunk.element_id, 'Chunk')} > @@ -169,7 +163,6 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { Similarity Score: {chunk?.score}
    handleChunkClick(chunk.element_id, 'Chunk')} > @@ -196,7 +189,6 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { Similarity Score: {chunk?.score}
    handleChunkClick(chunk.element_id, 'Chunk')} > @@ -228,7 +220,6 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => {
    handleChunkClick(chunk.element_id, 'Chunk')} > diff --git a/frontend/src/components/ChatBot/CommunitiesInfo.tsx b/frontend/src/components/ChatBot/CommunitiesInfo.tsx index bc8e5e8d3..005eb7ac6 100644 --- a/frontend/src/components/ChatBot/CommunitiesInfo.tsx +++ b/frontend/src/components/ChatBot/CommunitiesInfo.tsx @@ -13,18 +13,17 @@ const CommunitiesInfo: FC = ({ loading, communities, mode }) = const [neoRels, setNeoRels] = useState([]); const [openGraphView, setOpenGraphView] = useState(false); const [viewPoint, setViewPoint] = useState(''); - const [loadingGraphView, setLoadingGraphView] = useState(false); + const [graphLoading, setGraphLoading] = useState(false); const handleCommunityClick = (elementId: string, viewMode: string) => { + setOpenGraphView(true); + setViewPoint('chatInfoView'); handleGraphNodeClick( userCredentials as UserCredentials, elementId, viewMode, setNeoNodes, setNeoRels, - setOpenGraphView, - setViewPoint, - setLoadingGraphView ); }; @@ -42,7 +41,6 @@ const CommunitiesInfo: FC = ({ loading, communities, mode }) =
    handleCommunityClick(community.element_id, 'chatInfoView')} >{`ID : ${community.id}`} diff --git a/frontend/src/components/ChatBot/EntitiesInfo.tsx b/frontend/src/components/ChatBot/EntitiesInfo.tsx index 80e4fdafa..c1982a2c8 100644 --- a/frontend/src/components/ChatBot/EntitiesInfo.tsx +++ b/frontend/src/components/ChatBot/EntitiesInfo.tsx @@ -14,7 +14,6 @@ const EntitiesInfo: FC = ({ loading, mode, graphonly_entities, in const [neoRels, setNeoRels] = useState([]); const [openGraphView, setOpenGraphView] = useState(false); const [viewPoint, setViewPoint] = useState(''); - const [loadingGraphView, setLoadingGraphView] = useState(false); const groupedEntities = useMemo<{ [key: string]: GroupedEntity }>(() => { const items = infoEntities.reduce((acc, entity) => { @@ -44,15 +43,14 @@ const EntitiesInfo: FC = ({ loading, mode, graphonly_entities, in }, [labelCounts]); const handleEntityClick = (elementId: string, viewMode: string) => { + setOpenGraphView(true); + setViewPoint('chatInfoView'); handleGraphNodeClick( userCredentials as UserCredentials, elementId, viewMode, setNeoNodes, setNeoRels, - setOpenGraphView, - setViewPoint, - setLoadingGraphView ); }; @@ -69,9 +67,7 @@ const EntitiesInfo: FC = ({ loading, mode, graphonly_entities, in ? graphonly_entities.map((label, index) => (
    • {Object.keys(label).map((key) => ( @@ -118,7 +114,6 @@ const EntitiesInfo: FC = ({ loading, mode, graphonly_entities, in handleEntityClick(textId!, 'chatInfoView')} - className={loadingGraphView ? 'cursor-wait' : 'cursor-pointer'} > {text} diff --git a/frontend/src/components/ChatBot/chatInfo.ts b/frontend/src/components/ChatBot/chatInfo.ts index c7e990ae7..ba0183c2b 100644 --- a/frontend/src/components/ChatBot/chatInfo.ts +++ b/frontend/src/components/ChatBot/chatInfo.ts @@ -1,5 +1,6 @@ import { getNeighbors } from '../../services/GraphQuery'; import { NeoNode, NeoRelationship, UserCredentials } from '../../types'; +import { graphLabels } from '../../utils/Constants'; export const handleGraphNodeClick = async ( userCredentials: UserCredentials, @@ -7,18 +8,12 @@ export const handleGraphNodeClick = async ( viewMode: string, setNeoNodes: React.Dispatch>, setNeoRels: React.Dispatch>, - setOpenGraphView: React.Dispatch>, - setViewPoint: React.Dispatch>, - setLoadingGraphView?: React.Dispatch> ) => { - if (setLoadingGraphView) { - setLoadingGraphView(true); - } try { const result = await getNeighbors(userCredentials, elementId); if (result && result.data.data.nodes.length > 0) { let { nodes } = result.data.data; - if (viewMode === 'Chunk') { + if (viewMode === graphLabels.chatInfoView) { nodes = nodes.filter((node: NeoNode) => node.labels.length === 1 && node.properties.id !== null); } const nodeIds = new Set(nodes.map((node: NeoNode) => node.element_id)); @@ -27,14 +22,8 @@ export const handleGraphNodeClick = async ( ); setNeoNodes(nodes); setNeoRels(relationships); - setOpenGraphView(true); - setViewPoint('chatInfoView'); } } catch (error: any) { console.error('Error fetching neighbors:', error); - } finally { - if (setLoadingGraphView) { - setLoadingGraphView(false); - } } }; diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index cab5a2673..594af8628 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -117,10 +117,11 @@ const Content: React.FC = ({ setProcessedCount, setchatModes, } = useFileContext(); - const [viewPoint, setViewPoint] = useState<'tableView' | 'showGraphView' | 'chatInfoView'>('tableView'); + const [viewPoint, setViewPoint] = useState<'tableView' | 'showGraphView' | 'chatInfoView'|'neighborView'>('tableView'); const [showDeletePopUp, setshowDeletePopUp] = useState(false); const [deleteLoading, setdeleteLoading] = useState(false); const [searchParams] = useSearchParams(); + const [graphLoading, setGraphLoading] = useState(false); const { updateStatusForLargeFiles } = useServerSideEvent( (inMinutes, time, fileName) => { @@ -992,4 +993,4 @@ const Content: React.FC = ({ ); }; -export default Content; +export default Content; \ No newline at end of file diff --git a/frontend/src/components/FileTable.tsx b/frontend/src/components/FileTable.tsx index 8cc8d48ed..42b82572a 100644 --- a/frontend/src/components/FileTable.tsx +++ b/frontend/src/components/FileTable.tsx @@ -962,4 +962,4 @@ const FileTable = forwardRef((props, ref) => { ); }); -export default FileTable; +export default FileTable; \ No newline at end of file diff --git a/frontend/src/components/Graph/GraphViewModal.tsx b/frontend/src/components/Graph/GraphViewModal.tsx index e50f215d1..28574d30a 100644 --- a/frontend/src/components/Graph/GraphViewModal.tsx +++ b/frontend/src/components/Graph/GraphViewModal.tsx @@ -31,6 +31,7 @@ import CheckboxSelection from './CheckboxSelection'; import ResultOverview from './ResultOverview'; import { ResizePanelDetails } from './ResizePanel'; import GraphPropertiesPanel from './GraphPropertiesPanel'; +import { useGraphContext } from '../../context/GraphLoading'; const GraphViewModal: React.FunctionComponent = ({ open, @@ -46,7 +47,6 @@ const GraphViewModal: React.FunctionComponent = ({ const [relationships, setRelationships] = useState([]); const [allNodes, setAllNodes] = useState([]); const [allRelationships, setAllRelationships] = useState([]); - const [loading, setLoading] = useState(false); const [status, setStatus] = useState<'unknown' | 'success' | 'danger'>('unknown'); const [statusMessage, setStatusMessage] = useState(''); const { userCredentials } = useCredentials(); @@ -57,15 +57,16 @@ const GraphViewModal: React.FunctionComponent = ({ const [graphType, setGraphType] = useState([]); const [disableRefresh, setDisableRefresh] = useState(false); const [selected, setSelected] = useState<{ type: EntityType; id: string } | undefined>(undefined); + const { loadingGraph, setLoadingGraph } = useGraphContext(); const graphQuery: string = graphType.includes('DocumentChunk') && graphType.includes('Entities') ? queryMap.DocChunkEntities : graphType.includes('DocumentChunk') - ? queryMap.DocChunks - : graphType.includes('Entities') - ? queryMap.Entities - : ''; + ? queryMap.DocChunks + : graphType.includes('Entities') + ? queryMap.Entities + : ''; // fit graph to original position const handleZoomToFit = () => { @@ -107,10 +108,10 @@ const GraphViewModal: React.FunctionComponent = ({ const nodeRelationshipData = viewPoint === graphLabels.showGraphView ? await graphQueryAPI( - userCredentials as UserCredentials, - graphQuery, - selectedRows?.map((f) => f.name) - ) + userCredentials as UserCredentials, + graphQuery, + selectedRows?.map((f) => f.name) + ) : await graphQueryAPI(userCredentials as UserCredentials, graphQuery, [inspectedName ?? '']); return nodeRelationshipData; } catch (error: any) { @@ -138,19 +139,19 @@ const GraphViewModal: React.FunctionComponent = ({ setNodes(finalNodes); setRelationships(finalRels); setNewScheme(schemeVal); - setLoading(false); + setLoadingGraph(false); } setAllNodes(finalNodes); setAllRelationships(finalRels); setScheme(schemeVal); setDisableRefresh(false); } else { - setLoading(false); + setLoadingGraph(false); setStatus('danger'); setStatusMessage(`No Nodes and Relations for the ${inspectedName} file`); } } catch (error: any) { - setLoading(false); + setLoadingGraph(false); setStatus('danger'); setStatusMessage(error.message); } @@ -158,7 +159,7 @@ const GraphViewModal: React.FunctionComponent = ({ useEffect(() => { if (open) { - setLoading(true); + setLoadingGraph(true); setGraphType([]); if (viewPoint !== graphLabels.chatInfoView) { graphApi(); @@ -170,10 +171,10 @@ const GraphViewModal: React.FunctionComponent = ({ setNodes(finalNodes); setRelationships(finalRels); setNewScheme(schemeVal); - setLoading(false); + setLoadingGraph(false); } } - }, [open]); + }, [open, viewPoint]); useEffect(() => { if (debouncedQuery) { @@ -333,6 +334,7 @@ const GraphViewModal: React.FunctionComponent = ({ onDrag: true, }; + console.log('Graph viewModal', loadingGraph); return ( <> = ({ {checkBoxView && ( @@ -361,7 +363,7 @@ const GraphViewModal: React.FunctionComponent = ({
      - {loading ? ( + {loadingGraph ? (
      diff --git a/frontend/src/components/Layout/PageLayout.tsx b/frontend/src/components/Layout/PageLayout.tsx index 48e94c023..bf3082fc8 100644 --- a/frontend/src/components/Layout/PageLayout.tsx +++ b/frontend/src/components/Layout/PageLayout.tsx @@ -31,7 +31,6 @@ export default function PageLayoutNew({ const [shows3Modal, toggleS3Modal] = useReducer((s) => !s, false); const [showGCSModal, toggleGCSModal] = useReducer((s) => !s, false); const [showGenericModal, toggleGenericModal] = useReducer((s) => !s, false); - const toggleLeftDrawer = () => { if (largedesktops) { setIsLeftExpanded(!isLeftExpanded); diff --git a/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx b/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx index ad7e7b48e..76df732a4 100644 --- a/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx +++ b/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx @@ -460,4 +460,4 @@ export default function ConnectionModal({
      ); -} +} \ No newline at end of file diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx index 7140bb6b2..b30ba5302 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx @@ -30,6 +30,7 @@ import mergeDuplicateNodes from '../../../../services/MergeDuplicateEntities'; import { tokens } from '@neo4j-ndl/base'; import GraphViewModal from '../../../Graph/GraphViewModal'; import { handleGraphNodeClick } from '../../../ChatBot/chatInfo'; +import { useGraphContext } from '../../../../context/GraphLoading'; export default function DeduplicationTab() { const { breakpoints } = tokens; @@ -46,6 +47,7 @@ export default function DeduplicationTab() { const [openGraphView, setOpenGraphView] = useState(false); const [viewPoint, setViewPoint] = useState(''); const [nodesCount, setNodesCount] = useState(0); + const { setLoadingGraph } = useGraphContext(); const fetchDuplicateNodes = useCallback(async () => { try { setLoading(true); @@ -116,7 +118,8 @@ export default function DeduplicationTab() { setNeoNodes, setNeoRels, setOpenGraphView, - setViewPoint + setViewPoint, + setLoadingGraph ); }; diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx index bcc2597f1..2d147c9e2 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx @@ -21,6 +21,7 @@ import DeletePopUp from '../../DeletePopUp/DeletePopUp'; import { tokens } from '@neo4j-ndl/base'; import GraphViewModal from '../../../Graph/GraphViewModal'; import { handleGraphNodeClick } from '../../../ChatBot/chatInfo'; +import { useGraphContext } from '../../../../context/GraphLoading'; export default function DeletePopUpForOrphanNodes({ deleteHandler, loading, @@ -41,6 +42,7 @@ export default function DeletePopUpForOrphanNodes({ const [neoRels, setNeoRels] = useState([]); const [openGraphView, setOpenGraphView] = useState(false); const [viewPoint, setViewPoint] = useState(''); + const { setLoadingGraph } = useGraphContext(); const fetchOrphanNodes = useCallback(async () => { try { @@ -80,7 +82,8 @@ export default function DeletePopUpForOrphanNodes({ setNeoNodes, setNeoRels, setOpenGraphView, - setViewPoint + setViewPoint, + setLoadingGraph, ); }; diff --git a/frontend/src/components/QuickStarter.tsx b/frontend/src/components/QuickStarter.tsx index 1a4e169d2..43de7bd07 100644 --- a/frontend/src/components/QuickStarter.tsx +++ b/frontend/src/components/QuickStarter.tsx @@ -5,6 +5,7 @@ import { FileContextProvider } from '../context/UsersFiles'; import UserCredentialsWrapper from '../context/UserCredentials'; import AlertContextWrapper from '../context/Alert'; import { MessageContextWrapper } from '../context/UserMessages'; +import { GraphContextWrapper } from '../context/GraphLoading'; const QuickStarter: React.FunctionComponent = () => { const [showSettingsModal, setshowSettingsModal] = useState(false); @@ -19,14 +20,16 @@ const QuickStarter: React.FunctionComponent = () => { - -
      - - + + +
      + + + diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 6bc34d2da..6ebf26b45 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -574,6 +574,10 @@ export interface MessagesContextProviderProps { children: ReactNode; } +export interface GraphContextProviderProps { + children: ReactNode; +} + export interface Chunk { id: string; position: number; @@ -730,6 +734,11 @@ export interface MessageContextType { setClearHistoryData: Dispatch>; } +export interface GraphContextType { + loadingGraph: boolean; + setLoadingGraph: Dispatch>; +} + export interface DatabaseStatusProps { isConnected: boolean; isGdsActive: boolean; diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index 8d9289fd8..06d03d28b 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -12,26 +12,26 @@ export const llms = process.env?.VITE_LLM_MODELS?.trim() != '' ? (process.env.VITE_LLM_MODELS?.split(',') as string[]) : [ - 'diffbot', - 'openai_gpt_3.5', - 'openai_gpt_4o', - 'openai_gpt_4o_mini', - 'gemini_1.5_pro', - 'gemini_1.5_flash', - 'azure_ai_gpt_35', - 'azure_ai_gpt_4o', - 'ollama_llama3', - 'groq_llama3_70b', - 'anthropic_claude_3_5_sonnet', - 'fireworks_llama_v3p2_90b', - 'bedrock_claude_3_5_sonnet', - ]; + 'diffbot', + 'openai_gpt_3.5', + 'openai_gpt_4o', + 'openai_gpt_4o_mini', + 'gemini_1.5_pro', + 'gemini_1.5_flash', + 'azure_ai_gpt_35', + 'azure_ai_gpt_4o', + 'ollama_llama3', + 'groq_llama3_70b', + 'anthropic_claude_3_5_sonnet', + 'fireworks_llama_v3p2_90b', + 'bedrock_claude_3_5_sonnet', + ]; export const defaultLLM = llms?.includes('openai_gpt_4o') ? 'openai_gpt_4o' : llms?.includes('gemini_1.5_pro') - ? 'gemini_1.5_pro' - : 'diffbot'; + ? 'gemini_1.5_pro' + : 'diffbot'; export const supportedLLmsForRagas = [ 'openai_gpt_3.5', 'openai_gpt_4', @@ -76,40 +76,40 @@ export const chatModeReadableLables: Record = { export const chatModes = process.env?.VITE_CHAT_MODES?.trim() != '' ? process.env.VITE_CHAT_MODES?.split(',').map((mode) => ({ - mode: mode.trim(), - description: getDescriptionForChatMode(mode.trim()), - })) + mode: mode.trim(), + description: getDescriptionForChatMode(mode.trim()), + })) : [ - { - mode: chatModeLables.vector, - description: 'Performs semantic similarity search on text chunks using vector indexing.', - }, - { - mode: chatModeLables.graph, - description: 'Translates text to Cypher queries for precise data retrieval from a graph database.', - }, - { - mode: chatModeLables['graph+vector'], - description: 'Combines vector indexing and graph connections for contextually enhanced semantic search.', - }, - { - mode: chatModeLables.fulltext, - description: 'Conducts fast, keyword-based search using full-text indexing on text chunks.', - }, - { - mode: chatModeLables['graph+vector+fulltext'], - description: 'Integrates vector, graph, and full-text indexing for comprehensive search results.', - }, - { - mode: chatModeLables['entity search+vector'], - description: 'Uses vector indexing on entity nodes for highly relevant entity-based search.', - }, - { - mode: chatModeLables['global search+vector+fulltext'], - description: - 'Use vector and full-text indexing on community nodes to provide accurate, context-aware answers globally.', - }, - ]; + { + mode: chatModeLables.vector, + description: 'Performs semantic similarity search on text chunks using vector indexing.', + }, + { + mode: chatModeLables.graph, + description: 'Translates text to Cypher queries for precise data retrieval from a graph database.', + }, + { + mode: chatModeLables['graph+vector'], + description: 'Combines vector indexing and graph connections for contextually enhanced semantic search.', + }, + { + mode: chatModeLables.fulltext, + description: 'Conducts fast, keyword-based search using full-text indexing on text chunks.', + }, + { + mode: chatModeLables['graph+vector+fulltext'], + description: 'Integrates vector, graph, and full-text indexing for comprehensive search results.', + }, + { + mode: chatModeLables['entity search+vector'], + description: 'Uses vector indexing on entity nodes for highly relevant entity-based search.', + }, + { + mode: chatModeLables['global search+vector+fulltext'], + description: + 'Use vector and full-text indexing on community nodes to provide accurate, context-aware answers globally.', + }, + ]; export const chunkSize = process.env.VITE_CHUNK_SIZE ? parseInt(process.env.VITE_CHUNK_SIZE) : 1 * 1024 * 1024; export const timeperpage = process.env.VITE_TIME_PER_PAGE ? parseInt(process.env.VITE_TIME_PER_PAGE) : 50; @@ -291,6 +291,7 @@ export const graphLabels = { docChunk: 'Document & Chunk', community: 'Communities', noNodesRels: 'No Nodes and No relationships', + neighborView: 'neighborView' }; export const RESULT_STEP_SIZE = 25; diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index 6945c17ca..a65fe2362 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -130,6 +130,9 @@ export const getNodeCaption = (node: any) => { if (node.properties.fileName) { return node.properties.fileName; } + if(node.labels[0] === '__Community__'){ + return node.properties.title; + } return node.properties.id; }; From cd6b4c207b6f8f669529785ed2c40a00f5903250 Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Fri, 8 Nov 2024 19:51:09 +0530 Subject: [PATCH 226/292] disconnected nodes (#852) --- frontend/src/components/Graph/GraphViewModal.tsx | 5 ++--- frontend/src/utils/Utils.ts | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/Graph/GraphViewModal.tsx b/frontend/src/components/Graph/GraphViewModal.tsx index 28574d30a..e65a2c318 100644 --- a/frontend/src/components/Graph/GraphViewModal.tsx +++ b/frontend/src/components/Graph/GraphViewModal.tsx @@ -124,9 +124,7 @@ const GraphViewModal: React.FunctionComponent = ({ try { const result = await fetchData(); if (result && result.data.data.nodes.length > 0) { - const neoNodes = result.data.data.nodes - .map((f: Node) => f) - .filter((node: ExtendedNode) => node.labels.length === 1); + const neoNodes = result.data.data.nodes; const nodeIds = new Set(neoNodes.map((node: any) => node.element_id)); const neoRels = result.data.data.relationships .map((f: Relationship) => f) @@ -157,6 +155,7 @@ const GraphViewModal: React.FunctionComponent = ({ } }; + console.log('nodes', nodes); useEffect(() => { if (open) { setLoadingGraph(true); diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index a65fe2362..f407f21e0 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -159,11 +159,11 @@ export function extractPdfFileName(url: string): string { export const processGraphData = (neoNodes: ExtendedNode[], neoRels: ExtendedRelationship[]) => { const schemeVal: Scheme = {}; let iterator = 0; - const labels: string[] = neoNodes.map((f: any) => f.labels); + const labels: string[] = neoNodes.flatMap((f: any) => f.labels); for (let index = 0; index < labels.length; index++) { const label = labels[index]; if (schemeVal[label] == undefined) { - schemeVal[label] = calcWordColor(label[0]); + schemeVal[label] = calcWordColor(label); iterator += 1; } } From 399785f1a761146db678197047b776dc7bc0366d Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Fri, 8 Nov 2024 15:47:32 +0000 Subject: [PATCH 227/292] loading changes --- frontend/src/components/ChatBot/ChunkInfo.tsx | 15 +++++-- .../components/ChatBot/CommunitiesInfo.tsx | 10 +++-- .../src/components/ChatBot/EntitiesInfo.tsx | 13 +++++-- frontend/src/components/ChatBot/chatInfo.ts | 17 ++++++-- .../src/components/Graph/GraphViewModal.tsx | 39 +++++++++---------- .../Deduplication/index.tsx | 7 +--- .../DeleteTabForOrphanNodes/index.tsx | 7 +--- frontend/src/components/QuickStarter.tsx | 3 -- 8 files changed, 63 insertions(+), 48 deletions(-) diff --git a/frontend/src/components/ChatBot/ChunkInfo.tsx b/frontend/src/components/ChatBot/ChunkInfo.tsx index aa16d9451..b58ee2c4d 100644 --- a/frontend/src/components/ChatBot/ChunkInfo.tsx +++ b/frontend/src/components/ChatBot/ChunkInfo.tsx @@ -21,16 +21,18 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { const [neoRels, setNeoRels] = useState([]); const [openGraphView, setOpenGraphView] = useState(false); const [viewPoint, setViewPoint] = useState(''); + const [loadingGraphView, setLoadingGraphView] = useState(false); const handleChunkClick = (elementId: string, viewMode: string) => { - setOpenGraphView(true); - setViewPoint('chatInfoView'); handleGraphNodeClick( userCredentials as UserCredentials, elementId, viewMode, setNeoNodes, setNeoRels, + setOpenGraphView, + setViewPoint, + setLoadingGraphView ); }; @@ -70,6 +72,7 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => {
      handleChunkClick(chunk.element_id, 'Chunk')} > {'View Graph'} @@ -97,6 +100,7 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => {
      handleChunkClick(chunk.element_id, 'Chunk')} > @@ -119,6 +123,7 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { Similarity Score: {chunk?.score}
      handleChunkClick(chunk.element_id, 'Chunk')} > @@ -141,6 +146,7 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { Similarity Score: {chunk?.score}
      handleChunkClick(chunk.element_id, 'Chunk')} > @@ -163,6 +169,7 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { Similarity Score: {chunk?.score}
      handleChunkClick(chunk.element_id, 'Chunk')} > @@ -189,6 +196,7 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { Similarity Score: {chunk?.score}
      handleChunkClick(chunk.element_id, 'Chunk')} > @@ -220,6 +228,7 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => {
      handleChunkClick(chunk.element_id, 'Chunk')} > @@ -252,4 +261,4 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { ); }; -export default ChunkInfo; +export default ChunkInfo; \ No newline at end of file diff --git a/frontend/src/components/ChatBot/CommunitiesInfo.tsx b/frontend/src/components/ChatBot/CommunitiesInfo.tsx index 005eb7ac6..3c6899c5b 100644 --- a/frontend/src/components/ChatBot/CommunitiesInfo.tsx +++ b/frontend/src/components/ChatBot/CommunitiesInfo.tsx @@ -13,17 +13,18 @@ const CommunitiesInfo: FC = ({ loading, communities, mode }) = const [neoRels, setNeoRels] = useState([]); const [openGraphView, setOpenGraphView] = useState(false); const [viewPoint, setViewPoint] = useState(''); - const [graphLoading, setGraphLoading] = useState(false); + const [loadingGraphView, setLoadingGraphView] = useState(false); const handleCommunityClick = (elementId: string, viewMode: string) => { - setOpenGraphView(true); - setViewPoint('chatInfoView'); handleGraphNodeClick( userCredentials as UserCredentials, elementId, viewMode, setNeoNodes, setNeoRels, + setOpenGraphView, + setViewPoint, + setLoadingGraphView ); }; @@ -41,6 +42,7 @@ const CommunitiesInfo: FC = ({ loading, communities, mode }) =
      handleCommunityClick(community.element_id, 'chatInfoView')} >{`ID : ${community.id}`} @@ -73,4 +75,4 @@ const CommunitiesInfo: FC = ({ loading, communities, mode }) = ); }; -export default CommunitiesInfo; +export default CommunitiesInfo; \ No newline at end of file diff --git a/frontend/src/components/ChatBot/EntitiesInfo.tsx b/frontend/src/components/ChatBot/EntitiesInfo.tsx index c1982a2c8..22eca8a57 100644 --- a/frontend/src/components/ChatBot/EntitiesInfo.tsx +++ b/frontend/src/components/ChatBot/EntitiesInfo.tsx @@ -14,6 +14,7 @@ const EntitiesInfo: FC = ({ loading, mode, graphonly_entities, in const [neoRels, setNeoRels] = useState([]); const [openGraphView, setOpenGraphView] = useState(false); const [viewPoint, setViewPoint] = useState(''); + const [loadingGraphView, setLoadingGraphView] = useState(false); const groupedEntities = useMemo<{ [key: string]: GroupedEntity }>(() => { const items = infoEntities.reduce((acc, entity) => { @@ -43,14 +44,15 @@ const EntitiesInfo: FC = ({ loading, mode, graphonly_entities, in }, [labelCounts]); const handleEntityClick = (elementId: string, viewMode: string) => { - setOpenGraphView(true); - setViewPoint('chatInfoView'); handleGraphNodeClick( userCredentials as UserCredentials, elementId, viewMode, setNeoNodes, setNeoRels, + setOpenGraphView, + setViewPoint, + setLoadingGraphView ); }; @@ -67,7 +69,9 @@ const EntitiesInfo: FC = ({ loading, mode, graphonly_entities, in ? graphonly_entities.map((label, index) => (
      • {Object.keys(label).map((key) => ( @@ -114,6 +118,7 @@ const EntitiesInfo: FC = ({ loading, mode, graphonly_entities, in handleEntityClick(textId!, 'chatInfoView')} + className={loadingGraphView ? 'cursor-wait' : 'cursor-pointer'} > {text} @@ -141,4 +146,4 @@ const EntitiesInfo: FC = ({ loading, mode, graphonly_entities, in ); }; -export default EntitiesInfo; +export default EntitiesInfo; \ No newline at end of file diff --git a/frontend/src/components/ChatBot/chatInfo.ts b/frontend/src/components/ChatBot/chatInfo.ts index ba0183c2b..1a229dc70 100644 --- a/frontend/src/components/ChatBot/chatInfo.ts +++ b/frontend/src/components/ChatBot/chatInfo.ts @@ -1,6 +1,5 @@ import { getNeighbors } from '../../services/GraphQuery'; import { NeoNode, NeoRelationship, UserCredentials } from '../../types'; -import { graphLabels } from '../../utils/Constants'; export const handleGraphNodeClick = async ( userCredentials: UserCredentials, @@ -8,12 +7,18 @@ export const handleGraphNodeClick = async ( viewMode: string, setNeoNodes: React.Dispatch>, setNeoRels: React.Dispatch>, + setOpenGraphView: React.Dispatch>, + setViewPoint: React.Dispatch>, + setLoadingGraphView?: React.Dispatch> ) => { + if (setLoadingGraphView) { + setLoadingGraphView(true); + } try { const result = await getNeighbors(userCredentials, elementId); if (result && result.data.data.nodes.length > 0) { let { nodes } = result.data.data; - if (viewMode === graphLabels.chatInfoView) { + if (viewMode === 'Chunk') { nodes = nodes.filter((node: NeoNode) => node.labels.length === 1 && node.properties.id !== null); } const nodeIds = new Set(nodes.map((node: NeoNode) => node.element_id)); @@ -22,8 +27,14 @@ export const handleGraphNodeClick = async ( ); setNeoNodes(nodes); setNeoRels(relationships); + setOpenGraphView(true); + setViewPoint('chatInfoView'); } } catch (error: any) { console.error('Error fetching neighbors:', error); + } finally { + if (setLoadingGraphView) { + setLoadingGraphView(false); + } } -}; +}; \ No newline at end of file diff --git a/frontend/src/components/Graph/GraphViewModal.tsx b/frontend/src/components/Graph/GraphViewModal.tsx index e65a2c318..ac35a93ae 100644 --- a/frontend/src/components/Graph/GraphViewModal.tsx +++ b/frontend/src/components/Graph/GraphViewModal.tsx @@ -31,7 +31,6 @@ import CheckboxSelection from './CheckboxSelection'; import ResultOverview from './ResultOverview'; import { ResizePanelDetails } from './ResizePanel'; import GraphPropertiesPanel from './GraphPropertiesPanel'; -import { useGraphContext } from '../../context/GraphLoading'; const GraphViewModal: React.FunctionComponent = ({ open, @@ -47,6 +46,7 @@ const GraphViewModal: React.FunctionComponent = ({ const [relationships, setRelationships] = useState([]); const [allNodes, setAllNodes] = useState([]); const [allRelationships, setAllRelationships] = useState([]); + const [loading, setLoading] = useState(false); const [status, setStatus] = useState<'unknown' | 'success' | 'danger'>('unknown'); const [statusMessage, setStatusMessage] = useState(''); const { userCredentials } = useCredentials(); @@ -57,16 +57,15 @@ const GraphViewModal: React.FunctionComponent = ({ const [graphType, setGraphType] = useState([]); const [disableRefresh, setDisableRefresh] = useState(false); const [selected, setSelected] = useState<{ type: EntityType; id: string } | undefined>(undefined); - const { loadingGraph, setLoadingGraph } = useGraphContext(); const graphQuery: string = graphType.includes('DocumentChunk') && graphType.includes('Entities') ? queryMap.DocChunkEntities : graphType.includes('DocumentChunk') - ? queryMap.DocChunks - : graphType.includes('Entities') - ? queryMap.Entities - : ''; + ? queryMap.DocChunks + : graphType.includes('Entities') + ? queryMap.Entities + : ''; // fit graph to original position const handleZoomToFit = () => { @@ -108,10 +107,10 @@ const GraphViewModal: React.FunctionComponent = ({ const nodeRelationshipData = viewPoint === graphLabels.showGraphView ? await graphQueryAPI( - userCredentials as UserCredentials, - graphQuery, - selectedRows?.map((f) => f.name) - ) + userCredentials as UserCredentials, + graphQuery, + selectedRows?.map((f) => f.name) + ) : await graphQueryAPI(userCredentials as UserCredentials, graphQuery, [inspectedName ?? '']); return nodeRelationshipData; } catch (error: any) { @@ -137,28 +136,27 @@ const GraphViewModal: React.FunctionComponent = ({ setNodes(finalNodes); setRelationships(finalRels); setNewScheme(schemeVal); - setLoadingGraph(false); + setLoading(false); } setAllNodes(finalNodes); setAllRelationships(finalRels); setScheme(schemeVal); setDisableRefresh(false); } else { - setLoadingGraph(false); + setLoading(false); setStatus('danger'); setStatusMessage(`No Nodes and Relations for the ${inspectedName} file`); } } catch (error: any) { - setLoadingGraph(false); + setLoading(false); setStatus('danger'); setStatusMessage(error.message); } }; - console.log('nodes', nodes); useEffect(() => { if (open) { - setLoadingGraph(true); + setLoading(true); setGraphType([]); if (viewPoint !== graphLabels.chatInfoView) { graphApi(); @@ -170,10 +168,10 @@ const GraphViewModal: React.FunctionComponent = ({ setNodes(finalNodes); setRelationships(finalRels); setNewScheme(schemeVal); - setLoadingGraph(false); + setLoading(false); } } - }, [open, viewPoint]); + }, [open]); useEffect(() => { if (debouncedQuery) { @@ -333,7 +331,6 @@ const GraphViewModal: React.FunctionComponent = ({ onDrag: true, }; - console.log('Graph viewModal', loadingGraph); return ( <> = ({ {checkBoxView && ( @@ -362,7 +359,7 @@ const GraphViewModal: React.FunctionComponent = ({
        - {loadingGraph ? ( + {loading ? (
        @@ -448,4 +445,4 @@ const GraphViewModal: React.FunctionComponent = ({ ); }; -export default GraphViewModal; +export default GraphViewModal; \ No newline at end of file diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx index b30ba5302..330f5f657 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx @@ -30,7 +30,6 @@ import mergeDuplicateNodes from '../../../../services/MergeDuplicateEntities'; import { tokens } from '@neo4j-ndl/base'; import GraphViewModal from '../../../Graph/GraphViewModal'; import { handleGraphNodeClick } from '../../../ChatBot/chatInfo'; -import { useGraphContext } from '../../../../context/GraphLoading'; export default function DeduplicationTab() { const { breakpoints } = tokens; @@ -47,7 +46,6 @@ export default function DeduplicationTab() { const [openGraphView, setOpenGraphView] = useState(false); const [viewPoint, setViewPoint] = useState(''); const [nodesCount, setNodesCount] = useState(0); - const { setLoadingGraph } = useGraphContext(); const fetchDuplicateNodes = useCallback(async () => { try { setLoading(true); @@ -118,8 +116,7 @@ export default function DeduplicationTab() { setNeoNodes, setNeoRels, setOpenGraphView, - setViewPoint, - setLoadingGraph + setViewPoint ); }; @@ -355,4 +352,4 @@ export default function DeduplicationTab() { )} ); -} +} \ No newline at end of file diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx index 2d147c9e2..6d4daae10 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx @@ -21,7 +21,6 @@ import DeletePopUp from '../../DeletePopUp/DeletePopUp'; import { tokens } from '@neo4j-ndl/base'; import GraphViewModal from '../../../Graph/GraphViewModal'; import { handleGraphNodeClick } from '../../../ChatBot/chatInfo'; -import { useGraphContext } from '../../../../context/GraphLoading'; export default function DeletePopUpForOrphanNodes({ deleteHandler, loading, @@ -42,7 +41,6 @@ export default function DeletePopUpForOrphanNodes({ const [neoRels, setNeoRels] = useState([]); const [openGraphView, setOpenGraphView] = useState(false); const [viewPoint, setViewPoint] = useState(''); - const { setLoadingGraph } = useGraphContext(); const fetchOrphanNodes = useCallback(async () => { try { @@ -82,8 +80,7 @@ export default function DeletePopUpForOrphanNodes({ setNeoNodes, setNeoRels, setOpenGraphView, - setViewPoint, - setLoadingGraph, + setViewPoint ); }; @@ -318,4 +315,4 @@ export default function DeletePopUpForOrphanNodes({ )} ); -} +} \ No newline at end of file diff --git a/frontend/src/components/QuickStarter.tsx b/frontend/src/components/QuickStarter.tsx index 43de7bd07..4dc4b4a0a 100644 --- a/frontend/src/components/QuickStarter.tsx +++ b/frontend/src/components/QuickStarter.tsx @@ -5,7 +5,6 @@ import { FileContextProvider } from '../context/UsersFiles'; import UserCredentialsWrapper from '../context/UserCredentials'; import AlertContextWrapper from '../context/Alert'; import { MessageContextWrapper } from '../context/UserMessages'; -import { GraphContextWrapper } from '../context/GraphLoading'; const QuickStarter: React.FunctionComponent = () => { const [showSettingsModal, setshowSettingsModal] = useState(false); @@ -20,7 +19,6 @@ const QuickStarter: React.FunctionComponent = () => { -
        { closeSettingModal={closeSettingModal} /> - From 686ed95dc87c69fe89022563aa3306fb2bfa6c4a Mon Sep 17 00:00:00 2001 From: karanchellani <142801957+karanchellani@users.noreply.github.com> Date: Mon, 11 Nov 2024 13:25:13 +0530 Subject: [PATCH 228/292] Update score.py --- backend/score.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/score.py b/backend/score.py index 93a8c55fa..bbe471e48 100644 --- a/backend/score.py +++ b/backend/score.py @@ -33,7 +33,7 @@ from Secweb.ContentSecurityPolicy import ContentSecurityPolicy from Secweb.XContentTypeOptions import XContentTypeOptions from Secweb.XFrameOptions import XFrame -from fastapi.middleware.gzip import GZipMiddleware +#from fastapi.middleware.gzip import GZipMiddleware from src.ragas_eval import * logger = CustomLogger() @@ -55,7 +55,7 @@ def sick(): app.add_middleware(ContentSecurityPolicy, Option={'default-src': ["'self'"], 'base-uri': ["'self'"], 'block-all-mixed-content': []}, script_nonce=False, style_nonce=False, report_only=False) app.add_middleware(XContentTypeOptions) app.add_middleware(XFrame, Option={'X-Frame-Options': 'DENY'}) -app.add_middleware(GZipMiddleware, minimum_size=1000, compresslevel=5) +#app.add_middleware(GZipMiddleware, minimum_size=1000, compresslevel=5) app.add_middleware( CORSMiddleware, From 4f1af1820fc30b25f86c45d17154caac2bc416ca Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Tue, 12 Nov 2024 11:24:45 +0000 Subject: [PATCH 229/292] added middleware --- backend/score.py | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/backend/score.py b/backend/score.py index bbe471e48..03fb75de9 100644 --- a/backend/score.py +++ b/backend/score.py @@ -19,7 +19,7 @@ from src.communities import create_communities from src.neighbours import get_neighbour_nodes import json -from typing import List, Mapping +from typing import List, Mapping, Union from starlette.middleware.sessions import SessionMiddleware import google_auth_oauthlib.flow from google.oauth2.credentials import Credentials @@ -33,8 +33,10 @@ from Secweb.ContentSecurityPolicy import ContentSecurityPolicy from Secweb.XContentTypeOptions import XContentTypeOptions from Secweb.XFrameOptions import XFrame -#from fastapi.middleware.gzip import GZipMiddleware +from fastapi.middleware.gzip import GZipMiddleware from src.ragas_eval import * +from starlette.types import ASGIApp, Message, Receive, Scope, Send +import gzip logger = CustomLogger() CHUNK_DIR = os.path.join(os.path.dirname(__file__), "chunks") @@ -49,14 +51,42 @@ def healthy(): def sick(): return False - +class CustomGZipMiddleware: + def __init__( + self, + app: ASGIApp, + paths: List[str], + minimum_size: int = 1000, + compresslevel: int = 5 + ): + self.app = app + self.paths = paths + self.minimum_size = minimum_size + self.compresslevel = compresslevel + + async def __call__(self, scope: Scope, receive: Receive, send: Send): + if scope["type"] != "http": + return await self.app(scope, receive, send) + + path = scope["path"] + should_compress = any(path.startswith(gzip_path) for gzip_path in self.paths) + + if not should_compress: + return await self.app(scope, receive, send) + + gzip_middleware = GZipMiddleware( + app=self.app, + minimum_size=self.minimum_size, + compresslevel=self.compresslevel + ) + await gzip_middleware(scope, receive, send) app = FastAPI() # SecWeb(app=app, Option={'referrer': False, 'xframe': False}) app.add_middleware(ContentSecurityPolicy, Option={'default-src': ["'self'"], 'base-uri': ["'self'"], 'block-all-mixed-content': []}, script_nonce=False, style_nonce=False, report_only=False) app.add_middleware(XContentTypeOptions) app.add_middleware(XFrame, Option={'X-Frame-Options': 'DENY'}) #app.add_middleware(GZipMiddleware, minimum_size=1000, compresslevel=5) - +app.add_middleware(CustomGZipMiddleware, minimum_size=1000, compresslevel=5,paths=["/sources_list","/url/scan","/extract","/chat_bot","/chunk_entities","/get_neighbours","/graph_query","/schema","/populate_graph_schema","/get_unconnected_nodes_list","/get_duplicate_nodes","/fetch_chunktext"]) app.add_middleware( CORSMiddleware, allow_origins=["*"], From 1c29940f35d1a4029371e3340983e308ce0e8850 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Tue, 12 Nov 2024 11:32:27 +0000 Subject: [PATCH 230/292] removed the unused state --- frontend/src/components/Content.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 594af8628..8e8516666 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -121,7 +121,7 @@ const Content: React.FC = ({ const [showDeletePopUp, setshowDeletePopUp] = useState(false); const [deleteLoading, setdeleteLoading] = useState(false); const [searchParams] = useSearchParams(); - const [graphLoading, setGraphLoading] = useState(false); + const { updateStatusForLargeFiles } = useServerSideEvent( (inMinutes, time, fileName) => { From 1d14749dd36d9ac92823d93580dc1d9bd4da5062 Mon Sep 17 00:00:00 2001 From: aashipandya <156318202+aashipandya@users.noreply.github.com> Date: Thu, 14 Nov 2024 13:15:35 +0530 Subject: [PATCH 231/292] Youtube timestamp (#877) * youtube timestamp added to metadata * updated timestamps format while extraction * added fix for last chunk * updated default values of timestamp --------- Co-authored-by: kaustubh-darekar --- backend/src/chunkid_entities.py | 4 ++-- backend/src/document_sources/youtube.py | 17 ++++++++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/backend/src/chunkid_entities.py b/backend/src/chunkid_entities.py index 31ae07496..7d23e23dd 100644 --- a/backend/src/chunkid_entities.py +++ b/backend/src/chunkid_entities.py @@ -74,8 +74,8 @@ def process_chunk_data(chunk_data): for chunk in record["chunks"]: chunk.update(doc_properties) if chunk["fileSource"] == "youtube": - chunk["start_time"] = min(time_to_seconds(chunk["start_time"]),time_to_seconds(chunk["end_time"])) - chunk["end_time"] = time_to_seconds(chunk["end_time"]) + chunk["start_time"] = min(time_to_seconds(chunk.get('start_time',0)),time_to_seconds(chunk.get("end_time",0))) + chunk["end_time"] = time_to_seconds(chunk.get("end_time",0)) chunk_properties.append(chunk) return chunk_properties diff --git a/backend/src/document_sources/youtube.py b/backend/src/document_sources/youtube.py index e30de301e..dacda09f0 100644 --- a/backend/src/document_sources/youtube.py +++ b/backend/src/document_sources/youtube.py @@ -42,7 +42,7 @@ def get_youtube_combined_transcript(youtube_id): transcript_dict = get_youtube_transcript(youtube_id) transcript='' for td in transcript_dict: - transcript += ''.join(td['text']) + transcript += ''.join(td['text'])+" " return transcript except Exception as e: message = f"Youtube transcript is not available for youtube Id: {youtube_id}" @@ -83,9 +83,20 @@ def get_documents_from_youtube(url): # print(f'youtube page_content: {youtube_transcript[0].page_content}') # print(f'youtube id: {youtube_transcript[0].metadata["id"]}') # print(f'youtube title: {youtube_transcript[0].metadata["snippet"]["title"]}') - transcript= get_youtube_combined_transcript(match.group(1)) + transcript= get_youtube_transcript(match.group(1)) + transcript_content='' + counter = YOUTUBE_CHUNK_SIZE_SECONDS + pages = [] + for i, td in enumerate(transcript): + if td['start'] < counter: + transcript_content += ''.join(td['text'])+" " + else : + transcript_content += ''.join(td['text'])+" " + pages.append(Document(page_content=transcript_content.strip(), metadata={'start_timestamp':str(timedelta(seconds = counter-YOUTUBE_CHUNK_SIZE_SECONDS)).split('.')[0], 'end_timestamp':str(timedelta(seconds = td['start'])).split('.')[0]})) + counter += YOUTUBE_CHUNK_SIZE_SECONDS + transcript_content='' + pages.append(Document(page_content=transcript_content.strip(), metadata={'start_timestamp':str(timedelta(seconds = counter-YOUTUBE_CHUNK_SIZE_SECONDS)).split('.')[0], 'end_timestamp':str(timedelta(seconds =transcript[-1]['start'] if transcript else counter)).split('.')[0]})) # Handle empty transcript_pieces file_name = match.group(1)#youtube_transcript[0].metadata["snippet"]["title"] - pages = [Document(page_content=transcript)] return file_name, pages except Exception as e: error_message = str(e) From d6f4ac6a06699ed354d09b25642ff4176b9db6c1 Mon Sep 17 00:00:00 2001 From: kaustubh-darekar Date: Thu, 14 Nov 2024 14:51:37 +0530 Subject: [PATCH 232/292] Handled Nonetype error during global search. (#876) --- backend/src/QA_integration.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/src/QA_integration.py b/backend/src/QA_integration.py index b7fcbd665..12d974c3b 100644 --- a/backend/src/QA_integration.py +++ b/backend/src/QA_integration.py @@ -278,7 +278,9 @@ def retrieve_documents(doc_retriever, messages): except Exception as e: error_message = f"Error retrieving documents: {str(e)}" logging.error(error_message) - raise RuntimeError(error_message) + docs = None + transformed_question = None + return docs,transformed_question From a5a989de48de4e05f20017102008814840162f17 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Fri, 15 Nov 2024 13:15:15 +0530 Subject: [PATCH 233/292] Additional metrics using ground truth (#855) * Updating ragas metrics * added the service for additional metrics * additional metrics api * Adding Rouge to requirement * changes done for additional metrics for gemini model * Additional metrics changes related to gemini model * Adding Rouge_Score Version * Api Integration * payload changes * payload fix * Fixing Eval Error * Adding fact_score metric * code refactoring * table integration * data binding * Integrated additional metrics on multimodes * removed fact score * Removing Fact Score * fix: Multimode fix * custommiddleware for gzip * removed unused state * message changes * uncommented gzipmiddleware * code refactoring * removed settings modal code * Table UI Fixes * removed state * UX improvements for chunks popup * added the status check * ndl version changes * tip and dropdown changes * icon fixes * contextmenu fix * Box CSS fix * icon fixes * icon changes * IsRoot fix * added the tooltip for metrics * Menu fix inside modal * hover color fix * menu changes * format and lint fixes --------- Co-authored-by: a-s-poorna Co-authored-by: kaustubh-darekar --- backend/requirements.txt | 4 +- backend/score.py | 35 +- backend/src/QA_integration.py | 2 +- backend/src/ragas_eval.py | 48 + frontend/package.json | 9 +- frontend/src/App.css | 11 +- frontend/src/HOC/CustomModal.tsx | 7 +- frontend/src/HOC/withVisibility.tsx | 14 + frontend/src/assets/images/chunks.svg | 221 ++ .../src/components/ChatBot/ChatInfoModal.tsx | 319 ++- .../src/components/ChatBot/ChatModeToggle.tsx | 38 +- .../components/ChatBot/ChatModesSwitch.tsx | 16 +- frontend/src/components/ChatBot/Chatbot.tsx | 71 +- frontend/src/components/ChatBot/ChunkInfo.tsx | 47 +- .../components/ChatBot/CommunitiesInfo.tsx | 13 +- .../src/components/ChatBot/EntitiesInfo.tsx | 16 +- .../ChatBot/ExpandedChatButtonContainer.tsx | 42 +- .../components/ChatBot/MetricsCheckbox.tsx | 18 + .../src/components/ChatBot/MetricsTab.tsx | 26 +- .../components/ChatBot/MultiModeMetrics.tsx | 115 +- .../src/components/ChatBot/SourcesInfo.tsx | 12 +- frontend/src/components/ChatBot/chatInfo.ts | 2 +- frontend/src/components/Content.tsx | 89 +- .../components/DataSources/AWS/S3Modal.tsx | 56 +- .../components/DataSources/GCS/GCSModal.tsx | 64 +- .../components/DataSources/Local/DropZone.tsx | 10 +- .../Local/DropZoneForSmallLayouts.tsx | 23 +- frontend/src/components/Dropdown.tsx | 20 +- frontend/src/components/FileTable.tsx | 123 +- .../components/Graph/CheckboxSelection.tsx | 12 +- .../components/Graph/GraphPropertiesTable.tsx | 4 +- .../src/components/Graph/GraphViewModal.tsx | 32 +- .../src/components/Graph/ResultOverview.tsx | 22 +- .../src/components/Layout/DrawerChatbot.tsx | 2 +- .../src/components/Layout/DrawerDropzone.tsx | 8 +- frontend/src/components/Layout/Header.tsx | 2 +- frontend/src/components/Layout/PageLayout.tsx | 49 +- frontend/src/components/Layout/SideNav.tsx | 158 +- .../components/Popups/ChunkPopUp/index.tsx | 41 +- .../ConnectionModal/ConnectionModal.tsx | 98 +- .../VectorIndexMisMatchAlert.tsx | 4 +- .../Popups/DeletePopUp/DeletePopUp.tsx | 8 +- .../Deduplication/index.tsx | 45 +- .../DeleteTabForOrphanNodes/index.tsx | 41 +- .../EntityExtractionSetting.tsx | 38 +- .../SelectedJobList.tsx | 6 +- .../PostProcessingCheckList/index.tsx | 6 +- .../Popups/GraphEnhancementDialog/index.tsx | 61 +- .../LargeFilePopUp/ConfirmationDialog.tsx | 6 +- .../Popups/LargeFilePopUp/LargeFilesAlert.tsx | 22 +- .../Popups/RetryConfirmation/Index.tsx | 20 +- .../Popups/Settings/SchemaFromText.tsx | 31 +- .../Popups/Settings/SettingModal.tsx | 285 -- frontend/src/components/QuickStarter.tsx | 22 +- .../src/components/UI/ButtonWithToolTip.tsx | 30 +- frontend/src/components/UI/CustomCheckBox.tsx | 2 +- frontend/src/components/UI/CustomMenu.tsx | 30 + frontend/src/components/UI/ErrroBoundary.tsx | 4 +- frontend/src/components/UI/FallBackDialog.tsx | 2 +- .../src/components/UI/IconButtonToolTip.tsx | 37 +- frontend/src/components/UI/Menu.tsx | 50 - frontend/src/components/UI/TipWrapper.tsx | 14 +- .../WebSources/CustomSourceInput.tsx | 39 +- .../WebSources/GenericSourceModal.tsx | 36 +- frontend/src/context/UsersFiles.tsx | 4 +- frontend/src/services/AdditionalMetrics.ts | 31 + frontend/src/types.ts | 20 +- frontend/src/utils/Constants.ts | 134 +- frontend/src/utils/Utils.ts | 2 +- frontend/yarn.lock | 2520 +++++++++-------- 70 files changed, 2964 insertions(+), 2485 deletions(-) create mode 100644 frontend/src/HOC/withVisibility.tsx create mode 100644 frontend/src/assets/images/chunks.svg create mode 100644 frontend/src/components/ChatBot/MetricsCheckbox.tsx delete mode 100644 frontend/src/components/Popups/Settings/SettingModal.tsx create mode 100644 frontend/src/components/UI/CustomMenu.tsx delete mode 100644 frontend/src/components/UI/Menu.tsx create mode 100644 frontend/src/services/AdditionalMetrics.ts diff --git a/backend/requirements.txt b/backend/requirements.txt index 8fc0e0bda..5f0f5dc62 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -179,5 +179,5 @@ PyMuPDF==1.24.5 pypandoc==1.13 graphdatascience==1.10 Secweb==1.11.0 -ragas==0.1.14 - +ragas==0.2.2 +rouge_score==0.1.2 diff --git a/backend/score.py b/backend/score.py index 03fb75de9..d1ec0e68e 100644 --- a/backend/score.py +++ b/backend/score.py @@ -85,7 +85,6 @@ async def __call__(self, scope: Scope, receive: Receive, send: Send): app.add_middleware(ContentSecurityPolicy, Option={'default-src': ["'self'"], 'base-uri': ["'self'"], 'block-all-mixed-content': []}, script_nonce=False, style_nonce=False, report_only=False) app.add_middleware(XContentTypeOptions) app.add_middleware(XFrame, Option={'X-Frame-Options': 'DENY'}) -#app.add_middleware(GZipMiddleware, minimum_size=1000, compresslevel=5) app.add_middleware(CustomGZipMiddleware, minimum_size=1000, compresslevel=5,paths=["/sources_list","/url/scan","/extract","/chat_bot","/chunk_entities","/get_neighbours","/graph_query","/schema","/populate_graph_schema","/get_unconnected_nodes_list","/get_duplicate_nodes","/fetch_chunktext"]) app.add_middleware( CORSMiddleware, @@ -847,6 +846,40 @@ async def calculate_metric(question: str = Form(), ) finally: gc.collect() + + +@app.post('/additional_metrics') +async def calculate_additional_metrics(question: str = Form(), + context: str = Form(), + answer: str = Form(), + reference: str = Form(), + model: str = Form(), + mode: str = Form(), +): + try: + context_list = [str(item).strip() for item in json.loads(context)] if context else [] + answer_list = [str(item).strip() for item in json.loads(answer)] if answer else [] + mode_list = [str(item).strip() for item in json.loads(mode)] if mode else [] + result = await get_additional_metrics(question, context_list,answer_list, reference, model) + if result is None or "error" in result: + return create_api_response( + 'Failed', + message='Failed to calculate evaluation metrics.', + error=result.get("error", "Ragas evaluation returned null") + ) + data = {mode: {metric: result[i][metric] for metric in result[i]} for i, mode in enumerate(mode_list)} + return create_api_response('Success', data=data) + except Exception as e: + logging.exception(f"Error while calculating evaluation metrics: {e}") + return create_api_response( + 'Failed', + message="Error while calculating evaluation metrics", + error=str(e) + ) + finally: + gc.collect() + + @app.post("/fetch_chunktext") async def fetch_chunktext( diff --git a/backend/src/QA_integration.py b/backend/src/QA_integration.py index 12d974c3b..fff7d7923 100644 --- a/backend/src/QA_integration.py +++ b/backend/src/QA_integration.py @@ -662,7 +662,7 @@ def QA_RAG(graph,model, question, document_names, session_id, mode, write_access if document_names and not chat_mode_settings["document_filter"]: result = { "session_id": "", - "message": "This chat mode does support document selection", + "message": "Please deselect all documents in the table before using this chat mode", "info": { "sources": [], "model": "", diff --git a/backend/src/ragas_eval.py b/backend/src/ragas_eval.py index 8052cb9a2..687db37aa 100644 --- a/backend/src/ragas_eval.py +++ b/backend/src/ragas_eval.py @@ -7,6 +7,16 @@ from ragas import evaluate from ragas.metrics import answer_relevancy, faithfulness from src.shared.common_fn import load_embedding_model +from ragas.dataset_schema import SingleTurnSample +from ragas.metrics import BleuScore, RougeScore, SemanticSimilarity, ContextEntityRecall +from ragas.metrics._factual_correctness import FactualCorrectness +from ragas.llms import LangchainLLMWrapper +from langchain_openai import ChatOpenAI +from langchain.embeddings import OpenAIEmbeddings +from ragas.embeddings import LangchainEmbeddingsWrapper +import nltk + +nltk.download('punkt') load_dotenv() EMBEDDING_MODEL = os.getenv("RAGAS_EMBEDDING_MODEL") @@ -52,3 +62,41 @@ def get_ragas_metrics(question: str, context: list, answer: list, model: str): except Exception as e: logging.exception(f"Error during metrics evaluation: {e}") return {"error": str(e)} + + +async def get_additional_metrics(question: str, contexts: list, answers: list, reference: str, model_name: str): + """Calculates multiple metrics for given question, answers, contexts, and reference.""" + try: + if ("diffbot" in model_name) or ("ollama" in model_name): + raise ValueError(f"Unsupported model for evaluation: {model_name}") + llm, model_name = get_llm(model=model_name) + ragas_llm = LangchainLLMWrapper(llm) + embeddings = EMBEDDING_FUNCTION + embedding_model = LangchainEmbeddingsWrapper(embeddings=embeddings) + rouge_scorer = RougeScore() + semantic_scorer = SemanticSimilarity() + entity_recall_scorer = ContextEntityRecall() + entity_recall_scorer.llm = ragas_llm + semantic_scorer.embeddings = embedding_model + metrics = [] + for response, context in zip(answers, contexts): + sample = SingleTurnSample(response=response, reference=reference) + rouge_score = await rouge_scorer.single_turn_ascore(sample) + rouge_score = round(rouge_score,4) + semantic_score = await semantic_scorer.single_turn_ascore(sample) + semantic_score = round(semantic_score, 4) + if "gemini" in model_name: + entity_recall_score = "Not Available" + else: + entity_sample = SingleTurnSample(reference=reference, retrieved_contexts=[context]) + entity_recall_score = await entity_recall_scorer.single_turn_ascore(entity_sample) + entity_recall_score = round(entity_recall_score, 4) + metrics.append({ + "rouge_score": rouge_score, + "semantic_score": semantic_score, + "context_entity_recall_score": entity_recall_score + }) + return metrics + except Exception as e: + logging.exception("Error in get_additional_metrics") + return {"error": str(e)} \ No newline at end of file diff --git a/frontend/package.json b/frontend/package.json index 9e51f89fa..81d6f24b4 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -15,11 +15,12 @@ "@mui/material": "^5.15.10", "@mui/styled-engine": "^5.15.9", "@neo4j-devtools/word-color": "^0.0.8", - "@neo4j-ndl/base": "^2.12.7", - "@neo4j-ndl/react": "^2.16.9", - "@neo4j-nvl/base": "^0.3.3", - "@neo4j-nvl/react": "^0.3.3", + "@neo4j-ndl/base": "^3.0.10", + "@neo4j-ndl/react": "^3.0.17", + "@neo4j-nvl/base": "^0.3.6", + "@neo4j-nvl/react": "^0.3.6", "@react-oauth/google": "^0.12.1", + "@tanstack/react-table": "^8.20.5", "@types/uuid": "^9.0.7", "axios": "^1.6.5", "clsx": "^2.1.1", diff --git a/frontend/src/App.css b/frontend/src/App.css index e912a05e2..da6c34af6 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -25,7 +25,7 @@ } .contentWithExpansion { - width: calc(-840px + 100dvw); + width: calc(-807px + 100dvw); height: calc(100dvh - 58px); padding: 3px; display: flex; @@ -386,4 +386,13 @@ .custom-menu { min-width: 250px; max-width: 305px; +} +.ndl-modal-root{ + z-index: 39 !important; +} +.tbody-dark .ndl-data-grid-tr:hover { + --cell-background: rgb(60 63 68) !important; +} +.tbody-light .ndl-data-grid-tr:hover { + --cell-background: rgb(226 227 229) !important; } \ No newline at end of file diff --git a/frontend/src/HOC/CustomModal.tsx b/frontend/src/HOC/CustomModal.tsx index e756a092d..814a4343c 100644 --- a/frontend/src/HOC/CustomModal.tsx +++ b/frontend/src/HOC/CustomModal.tsx @@ -16,7 +16,7 @@ const CustomModal: React.FC = ({ return ( = ({ {status !== 'unknown' && ( setStatus('unknown')} type={status} name='Custom Banner' + usage='inline' /> )}
        {children}
        - diff --git a/frontend/src/HOC/withVisibility.tsx b/frontend/src/HOC/withVisibility.tsx new file mode 100644 index 000000000..057c38bd0 --- /dev/null +++ b/frontend/src/HOC/withVisibility.tsx @@ -0,0 +1,14 @@ +interface VisibilityProps { + isVisible: boolean; +} +export function withVisibility

        (WrappedComponent: React.ComponentType

        ) { + const VisibityControlled = (props: P & VisibilityProps) => { + if (props.isVisible === false) { + return null; + } + + return ; + }; + + return VisibityControlled; +} diff --git a/frontend/src/assets/images/chunks.svg b/frontend/src/assets/images/chunks.svg new file mode 100644 index 000000000..e1aa08f32 --- /dev/null +++ b/frontend/src/assets/images/chunks.svg @@ -0,0 +1,221 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index b3c47b4be..5aee9067a 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -3,34 +3,43 @@ import { Typography, Flex, Tabs, - CypherCodeBlock, - CypherCodeBlockProps, + Code, useCopyToClipboard, Banner, useMediaQuery, Button, + TextArea, + IconButton, + Accordion, } from '@neo4j-ndl/react'; import { DocumentDuplicateIconOutline, ClipboardDocumentCheckIconOutline } from '@neo4j-ndl/react/icons'; import '../../styling/info.css'; import Neo4jRetrievalLogo from '../../assets/images/Neo4jRetrievalLogo.png'; import { ExtendedNode, UserCredentials, chatInfoMessage } from '../../types'; -import { useContext, useEffect, useMemo, useState } from 'react'; +import { useEffect, useMemo, useReducer, useRef, useState } from 'react'; import GraphViewButton from '../Graph/GraphViewButton'; import { chunkEntitiesAPI } from '../../services/ChunkEntitiesInfo'; import { useCredentials } from '../../context/UserCredentials'; -import { ThemeWrapperContext } from '../../context/ThemeWrapper'; import { tokens } from '@neo4j-ndl/base'; import ChunkInfo from './ChunkInfo'; import EntitiesInfo from './EntitiesInfo'; import SourcesInfo from './SourcesInfo'; import CommunitiesInfo from './CommunitiesInfo'; -import { chatModeLables, chatModeReadableLables, supportedLLmsForRagas } from '../../utils/Constants'; +import { + chatModeLables, + chatModeReadableLables, + mergeNestedObjects, + supportedLLmsForRagas, +} from '../../utils/Constants'; import { Relationship } from '@neo4j-nvl/base'; import { getChatMetrics } from '../../services/GetRagasMetric'; import MetricsTab from './MetricsTab'; import { Stack } from '@mui/material'; import { capitalizeWithUnderscore, getNodes } from '../../utils/Utils'; import MultiModeMetrics from './MultiModeMetrics'; +import getAdditionalMetrics from '../../services/AdditionalMetrics'; +import { withVisibility } from '../../HOC/withVisibility'; +import MetricsCheckbox from './MetricsCheckbox'; const ChatInfoModal: React.FC = ({ sources, @@ -80,24 +89,40 @@ const ChatInfoModal: React.FC = ({ : 3 ); const { userCredentials } = useCredentials(); - const themeUtils = useContext(ThemeWrapperContext); const [, copy] = useCopyToClipboard(); const [copiedText, setcopiedText] = useState(false); const [showMetricsTable, setShowMetricsTable] = useState(Boolean(metricDetails)); const [showMultiModeMetrics, setShowMultiModeMetrics] = useState(Boolean(multiModelMetrics.length)); const [multiModeError, setMultiModeError] = useState(''); + const [enableReference, toggleReferenceVisibility] = useReducer((state: boolean) => !state, false); + const textAreaRef = useRef(null); + const [expandedItemIdValue, setExpandedId] = useState(null); + const [isAdditionalMetricsEnabled, setIsAdditionalMetricsEnabled] = useState( + multiModelMetrics.length > 0 && Object.keys(multiModelMetrics[0]).length > 3 + ? true + : multiModelMetrics.length > 0 && Object.keys(multiModelMetrics[0]).length <= 3 + ? false + : null + ); + const [isAdditionalMetricsWithSingleMode, setIsAdditionalMetricsWithSingleMode] = useState( + metricDetails != undefined && Object.keys(metricDetails).length > 2 + ? true + : metricDetails != undefined && Object.keys(metricDetails).length <= 2 + ? false + : null + ); - const actions: CypherCodeBlockProps['actions'] = useMemo( + const actions: React.ComponentProps>[] = useMemo( () => [ { title: 'copy', - 'aria-label': 'copy', + ariaLabel: 'copy', children: ( <> {copiedText ? ( ) : ( - + )} ), @@ -183,79 +208,126 @@ const ChatInfoModal: React.FC = ({ setActiveTab(tabId); }; const loadMetrics = async () => { - if (activeChatmodes) { - if (Object.keys(activeChatmodes).length <= 1) { - setShowMetricsTable(true); - const [defaultMode] = Object.keys(activeChatmodes); - try { - toggleMetricsLoading(); - const response = await getChatMetrics(metricquestion, [metriccontexts], [metricanswer], metricmodel, [ - defaultMode, - ]); - toggleMetricsLoading(); - if (response.data.status === 'Success') { - const data = response; - saveMetrics(data.data.data[defaultMode]); - } else { - throw new Error(response.data.error); - } - } catch (error) { - if (error instanceof Error) { - toggleMetricsLoading(); - console.log('Error in getting chat metrics', error); - saveMetrics({ faithfulness: 0, answer_relevancy: 0, error: error.message }); + // @ts-ignore + const referenceText = textAreaRef?.current?.value ?? ''; + const metricsPromise = []; + if (activeChatmodes != undefined && Object.keys(activeChatmodes).length <= 1) { + setShowMetricsTable(true); + const [defaultMode] = Object.keys(activeChatmodes); + try { + toggleMetricsLoading(); + metricsPromise.push( + getChatMetrics(metricquestion, [metriccontexts], [metricanswer], metricmodel, [defaultMode]) + ); + if (referenceText.trim() != '') { + metricsPromise.push( + getAdditionalMetrics(metricquestion, [metriccontexts], [metricanswer], referenceText, metricmodel, [ + defaultMode, + ]) + ); + } + const metricsResponse = await Promise.allSettled(metricsPromise); + const successresponse = []; + for (let index = 0; index < metricsResponse.length; index++) { + const metricPromise = metricsResponse[index]; + if (metricPromise.status === 'fulfilled' && metricPromise.value.data.status === 'Success') { + successresponse.push(metricPromise.value.data.data); } } - } else { - setShowMultiModeMetrics(true); + setIsAdditionalMetricsWithSingleMode(successresponse.length === 2); toggleMetricsLoading(); - const contextarray = Object.values(activeChatmodes).map((r) => { - return r.metric_contexts; - }); - const answerarray = Object.values(activeChatmodes).map((r) => { - return r.metric_answer; - }); - const modesarray = Object.keys(activeChatmodes).map((mode) => { - return mode; - }); - try { - const responses = await getChatMetrics( - metricquestion, - contextarray as string[], - answerarray as string[], - metricmodel, - modesarray - ); - toggleMetricsLoading(); - if (responses.data.status === 'Success') { - const modewisedata = responses.data.data; - const metricsdata = Object.entries(modewisedata).map(([mode, scores]) => { - return { mode, answer_relevancy: scores.answer_relevancy, faithfulness: scores.faithfulness }; - }); - saveMultimodemetrics(metricsdata); + const mergedState = successresponse.reduce((acc, cur) => { + if (acc[defaultMode]) { + acc[defaultMode] = { ...acc[defaultMode], ...cur[defaultMode] }; } else { - throw new Error(responses.data.error); + acc[defaultMode] = cur[defaultMode]; } - } catch (error) { + return acc; + }, {}); + saveMetrics(mergedState[defaultMode]); + } catch (error) { + if (error instanceof Error) { + setShowMetricsTable(false); toggleMetricsLoading(); console.log('Error in getting chat metrics', error); - if (error instanceof Error) { - setMultiModeError(error.message); + saveMetrics({ faithfulness: 0, answer_relevancy: 0, error: error.message }); + } + } + } else if (activeChatmodes != undefined) { + setShowMultiModeMetrics(true); + toggleMetricsLoading(); + const values = Object.values(activeChatmodes); + const keys = Object.keys(activeChatmodes); + const contextarray = values.map((r) => { + return r.metric_contexts; + }); + const answerarray = values.map((r) => { + return r.metric_answer; + }); + const modesarray = keys.map((mode) => { + return mode; + }); + try { + metricsPromise.push( + getChatMetrics(metricquestion, contextarray as string[], answerarray as string[], metricmodel, modesarray) + ); + if (referenceText.trim() != '') { + metricsPromise.push( + getAdditionalMetrics( + metricquestion, + contextarray as string[], + answerarray as string[], + referenceText, + metricmodel, + modesarray + ) + ); + } + const metricsResponse = await Promise.allSettled(metricsPromise); + toggleMetricsLoading(); + const successResponse = []; + for (let index = 0; index < metricsResponse.length; index++) { + const metricPromise = metricsResponse[index]; + if (metricPromise.status === 'fulfilled' && metricPromise.value.data.status === 'Success') { + successResponse.push(metricPromise.value.data.data); } } + setIsAdditionalMetricsEnabled(successResponse.length === 2); + const metricsdata = Object.entries(mergeNestedObjects(successResponse)).map(([mode, scores]) => { + return { mode, ...scores }; + }); + saveMultimodemetrics(metricsdata); + } catch (error) { + setShowMultiModeMetrics(false); + toggleMetricsLoading(); + console.log('Error in getting chat metrics', error); + if (error instanceof Error) { + setMultiModeError(error.message); + } } } }; - + const MetricsCheckBoxWithCheck = withVisibility(MetricsCheckbox); + const TextareaWithCheck = withVisibility(() => ( + + )); + const isMultiModes = useMemo( + () => activeChatmodes != null && Object.keys(activeChatmodes).length > 1, + [activeChatmodes] + ); + const isSingleMode = useMemo( + () => activeChatmodes != null && Object.keys(activeChatmodes).length <= 1, + [activeChatmodes] + ); return ( - - +

        +
        - +
        Retrieval information To generate this response, the process took {response_time} seconds, @@ -268,10 +340,12 @@ const ChatInfoModal: React.FC = ({ {' '} mode. - - +
        +
        {error?.length > 0 ? ( - {error} + + {error} + ) : ( {mode === chatModeLables['global search+vector+fulltext'] ? ( @@ -308,7 +382,7 @@ const ChatInfoModal: React.FC = ({ - + {!supportedLLmsForRagas.includes(metricmodel) && ( = ({ . } + usage='inline' > )} @@ -335,41 +410,88 @@ const ChatInfoModal: React.FC = ({ about 20 seconds . You'll see detailed scores shortly. - - - Faithfulness: Determines How accurately the answer reflects the - provided information - - - Answer Relevancy: Determines How well the answer addresses the - user's question. - - +
        + { + setExpandedId(e); + }} + > + + Determines How accurately the answer reflects the provided information. + + + Determines How well the answer addresses the user's question. + + {(isAdditionalMetricsWithSingleMode || isAdditionalMetricsEnabled) && ( + <> + + Determines How much the generated answer matches the reference answer, word-for-word + + + Determines How well the generated answer understands the meaning of the reference answer. + + + Determines Measures the recall of entities present in both reference and retrieved contexts + relative to the reference. + + + )} + +
        - {showMultiModeMetrics && activeChatmodes != null && Object.keys(activeChatmodes).length > 1 && ( + {showMultiModeMetrics && isMultiModes && ( )} - {showMetricsTable && activeChatmodes != null && Object.keys(activeChatmodes).length <= 1 && ( + {showMetricsTable && isSingleMode && ( )} - {!metricDetails && activeChatmodes != undefined && Object.keys(activeChatmodes).length <= 1 && ( - - )} - {!multiModelMetrics.length && activeChatmodes != undefined && Object.keys(activeChatmodes).length > 1 && ( + + + + + {isSingleMode && + (isAdditionalMetricsWithSingleMode === false || isAdditionalMetricsWithSingleMode === null) && ( + + )} + {isMultiModes && (isAdditionalMetricsEnabled === false || isAdditionalMetricsEnabled === null) && (
        ); }; export default ChatInfoModal; diff --git a/frontend/src/components/ChatBot/ChatModeToggle.tsx b/frontend/src/components/ChatBot/ChatModeToggle.tsx index 0a9a81e10..b99f06b96 100644 --- a/frontend/src/components/ChatBot/ChatModeToggle.tsx +++ b/frontend/src/components/ChatBot/ChatModeToggle.tsx @@ -1,33 +1,30 @@ import { StatusIndicator, Typography } from '@neo4j-ndl/react'; -import { useMemo, useEffect } from 'react'; import { useFileContext } from '../../context/UsersFiles'; -import CustomMenu from '../UI/Menu'; +import CustomMenu from '../UI/CustomMenu'; import { chatModeLables, chatModes as AvailableModes, chatModeReadableLables } from '../../utils/Constants'; import { capitalize } from '@mui/material'; import { capitalizeWithPlus } from '../../utils/Utils'; import { useCredentials } from '../../context/UserCredentials'; +import { useMemo } from 'react'; export default function ChatModeToggle({ menuAnchor, closeHandler = () => {}, open, - anchorPortal = true, - disableBackdrop = false, + isRoot, }: { - menuAnchor: HTMLElement | null; + menuAnchor: React.RefObject; closeHandler?: () => void; open: boolean; - anchorPortal?: boolean; - disableBackdrop?: boolean; + isRoot: boolean; }) { const { setchatModes, chatModes, postProcessingTasks } = useFileContext(); const isCommunityAllowed = postProcessingTasks.includes('enable_communities'); const { isGdsActive } = useCredentials(); - useEffect(() => { - if (!chatModes.length) { - setchatModes([chatModeLables['graph+vector+fulltext']]); - } - }, [chatModes.length]); + if (!chatModes.length) { + setchatModes([chatModeLables['graph+vector+fulltext']]); + } + const memoizedChatModes = useMemo(() => { return isGdsActive && isCommunityAllowed ? AvailableModes @@ -44,7 +41,6 @@ export default function ChatModeToggle({ } else { setchatModes((prev) => [...prev, m.mode]); } - closeHandler(); }; return { title: ( @@ -59,7 +55,10 @@ export default function ChatModeToggle({
    • ), - onClick: handleModeChange, + onClick: (e: React.MouseEvent) => { + handleModeChange(); + e.stopPropagation(); + }, disabledCondition: false, description: ( @@ -72,15 +71,8 @@ export default function ChatModeToggle({ ), }; }); - }, [chatModes, memoizedChatModes, closeHandler]); + }, [chatModes, memoizedChatModes]); return ( - + ); } diff --git a/frontend/src/components/ChatBot/ChatModesSwitch.tsx b/frontend/src/components/ChatBot/ChatModesSwitch.tsx index 4ace49af5..39d47507a 100644 --- a/frontend/src/components/ChatBot/ChatModesSwitch.tsx +++ b/frontend/src/components/ChatBot/ChatModesSwitch.tsx @@ -23,13 +23,13 @@ export default function ChatModesSwitch({ return ( switchToOtherMode(currentModeIndex - 1)} - aria-label='left' + ariaLabel='left' > - + switchToOtherMode(currentModeIndex + 1)} - aria-label='right' + ariaLabel='right' > - + ); diff --git a/frontend/src/components/ChatBot/Chatbot.tsx b/frontend/src/components/ChatBot/Chatbot.tsx index 3fa666e1e..5a7bf0121 100644 --- a/frontend/src/components/ChatBot/Chatbot.tsx +++ b/frontend/src/components/ChatBot/Chatbot.tsx @@ -42,22 +42,21 @@ import { downloadClickHandler, getDateTime } from '../../utils/Utils'; import ChatModesSwitch from './ChatModesSwitch'; import CommonActions from './CommonChatActions'; const InfoModal = lazy(() => import('./ChatInfoModal')); +if (typeof window !== 'undefined') { + if (!sessionStorage.getItem('session_id')) { + const id = uuidv4(); + sessionStorage.setItem('session_id', id); + } +} +const sessionId = sessionStorage.getItem('session_id') ?? ''; const Chatbot: FC = (props) => { - const { - messages: listMessages, - setMessages: setListMessages, - isLoading, - isFullScreen, - clear, - connectionStatus, - } = props; + const { messages: listMessages, setMessages: setListMessages, isLoading, isFullScreen, connectionStatus } = props; const [inputMessage, setInputMessage] = useState(''); const [loading, setLoading] = useState(isLoading); const { userCredentials } = useCredentials(); const { model, chatModes, selectedRows, filesData } = useFileContext(); const messagesEndRef = useRef(null); - const [sessionId, setSessionId] = useState(sessionStorage.getItem('session_id') ?? ''); const [showInfoModal, setShowInfoModal] = useState(false); const [sourcesModal, setSourcesModal] = useState([]); const [modelModal, setModelModal] = useState(''); @@ -123,13 +122,6 @@ const Chatbot: FC = (props) => { const saveCommunities = (chatCommunities: Community[]) => { setCommunities(chatCommunities); }; - useEffect(() => { - if (!sessionStorage.getItem('session_id')) { - const id = uuidv4(); - setSessionId(id); - sessionStorage.setItem('session_id', id); - } - }, []); const simulateTypingEffect = (messageId: number, response: ResponseMode, mode: string, message: string) => { let index = 0; @@ -319,19 +311,9 @@ const Chatbot: FC = (props) => { }; useEffect(() => { scrollToBottom(); - }, [listMessages]); - - useEffect(() => { setLoading(() => listMessages.some((msg) => msg.isLoading || msg.isTyping)); }, [listMessages]); - useEffect(() => { - if (clear) { - cancel(); - setListMessages((msgs) => msgs.map((msg) => ({ ...msg, speaking: false }))); - } - }, [clear]); - const handleCopy = (message: string, id: number) => { copy(message); setListMessages((msgs) => @@ -440,10 +422,10 @@ const Chatbot: FC = (props) => { className='-ml-4' hasStatus name='KM' - shape='square' size='x-large' source={ChatBotAvatar} status={connectionStatus ? 'online' : 'offline'} + shape='square' type='image' /> ) : ( @@ -451,9 +433,9 @@ const Chatbot: FC = (props) => { className='' hasStatus name='KM' - shape='square' size='x-large' status={connectionStatus ? 'online' : 'offline'} + shape='square' type='image' /> )} @@ -555,12 +537,14 @@ const Chatbot: FC = (props) => { className={`n-bg-palette-neutral-bg-default flex-grow-7 ${ isFullScreen ? 'w-[calc(100%-105px)]' : 'w-[70%]' }`} - aria-label='chatbot-input' - type='text' value={inputMessage} - fluid + isFluid onChange={handleInputChange} - name='chatbot-input' + htmlAttributes={{ + type: 'text', + 'aria-label': 'chatbot-input', + name: 'chatbot-input', + }} /> = (props) => { className: 'n-p-token-4 n-bg-palette-neutral-bg-weak n-rounded-lg', }} onClose={() => setShowInfoModal(false)} - open={showInfoModal} + isOpen={showInfoModal} size={activeChat?.currentMode === chatModeLables['entity search+vector'] ? 'large' : 'medium'} >
      { downloadClickHandler( { @@ -609,19 +596,21 @@ const Chatbot: FC = (props) => { ); }} > - + "" setShowInfoModal(false)} > - +
      = ({ loading, chunks, mode }) => { return ( <> {loading ? ( - +
      - +
      ) : chunks?.length > 0 ? (
        @@ -71,9 +71,10 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => {
      handleChunkClick(chunk.element_id, 'Chunk')} + htmlAttributes={{ + onClick: () => handleChunkClick(chunk.element_id, 'Chunk'), + }} > {'View Graph'} @@ -83,7 +84,7 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { <>
      - + = ({ loading, chunks, mode }) => { handleChunkClick(chunk.element_id, 'Chunk')} + htmlAttributes={{ + onClick: () => handleChunkClick(chunk.element_id, 'Chunk'), + }} > {'View Graph'} @@ -124,8 +126,9 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => {
      handleChunkClick(chunk.element_id, 'Chunk')} + htmlAttributes={{ + onClick: () => handleChunkClick(chunk.element_id, 'Chunk'), + }} > {'View Graph'} @@ -147,8 +150,9 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => {
      handleChunkClick(chunk.element_id, 'Chunk')} + htmlAttributes={{ + onClick: () => handleChunkClick(chunk.element_id, 'Chunk'), + }} > {'View Graph'} @@ -170,8 +174,9 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => {
      handleChunkClick(chunk.element_id, 'Chunk')} + htmlAttributes={{ + onClick: () => handleChunkClick(chunk.element_id, 'Chunk'), + }} > {'View Graph'} @@ -185,7 +190,7 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { <>
      - + {chunk?.url}
      @@ -197,8 +202,9 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => {
      handleChunkClick(chunk.element_id, 'Chunk')} + htmlAttributes={{ + onClick: () => handleChunkClick(chunk.element_id, 'Chunk'), + }} > {'View Graph'} @@ -229,8 +235,9 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => {
      handleChunkClick(chunk.element_id, 'Chunk')} + htmlAttributes={{ + onClick: () => handleChunkClick(chunk.element_id, 'Chunk'), + }} > {'View Graph'} @@ -261,4 +268,4 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { ); }; -export default ChunkInfo; \ No newline at end of file +export default ChunkInfo; diff --git a/frontend/src/components/ChatBot/CommunitiesInfo.tsx b/frontend/src/components/ChatBot/CommunitiesInfo.tsx index 3c6899c5b..30d533193 100644 --- a/frontend/src/components/ChatBot/CommunitiesInfo.tsx +++ b/frontend/src/components/ChatBot/CommunitiesInfo.tsx @@ -1,4 +1,4 @@ -import { Box, LoadingSpinner, Flex, Typography, TextLink } from '@neo4j-ndl/react'; +import { LoadingSpinner, Flex, Typography, TextLink } from '@neo4j-ndl/react'; import { FC, useState } from 'react'; import ReactMarkdown from 'react-markdown'; import { CommunitiesProps, UserCredentials } from '../../types'; @@ -31,9 +31,9 @@ const CommunitiesInfo: FC = ({ loading, communities, mode }) = return ( <> {loading ? ( - +
      - +
      ) : communities?.length > 0 ? (
        @@ -43,8 +43,9 @@ const CommunitiesInfo: FC = ({ loading, communities, mode }) = handleCommunityClick(community.element_id, 'chatInfoView')} + htmlAttributes={{ + onClick: () => handleCommunityClick(community.element_id, 'chatInfoView'), + }} >{`ID : ${community.id}`} {mode === chatModeLables['global search+vector+fulltext'] && community.score && ( @@ -75,4 +76,4 @@ const CommunitiesInfo: FC = ({ loading, communities, mode }) = ); }; -export default CommunitiesInfo; \ No newline at end of file +export default CommunitiesInfo; diff --git a/frontend/src/components/ChatBot/EntitiesInfo.tsx b/frontend/src/components/ChatBot/EntitiesInfo.tsx index 22eca8a57..0a90862a4 100644 --- a/frontend/src/components/ChatBot/EntitiesInfo.tsx +++ b/frontend/src/components/ChatBot/EntitiesInfo.tsx @@ -1,4 +1,4 @@ -import { Box, GraphLabel, LoadingSpinner, TextLink, Typography } from '@neo4j-ndl/react'; +import { GraphLabel, LoadingSpinner, TextLink, Typography } from '@neo4j-ndl/react'; import { FC, useMemo, useState } from 'react'; import { EntitiesProps, GroupedEntity, UserCredentials } from '../../types'; import { calcWordColor } from '@neo4j-devtools/word-color'; @@ -59,9 +59,9 @@ const EntitiesInfo: FC = ({ loading, mode, graphonly_entities, in return ( <> {loading ? ( - +
        - +
        ) : (mode !== 'graph' && Object.keys(groupedEntities)?.length > 0) || (mode == 'graph' && Object.keys(graphonly_entities)?.length > 0) ? (
          @@ -76,7 +76,7 @@ const EntitiesInfo: FC = ({ loading, mode, graphonly_entities, in
            {Object.keys(label).map((key) => (
          • - + {key} = ({ loading, mode, graphonly_entities, in key={index} className='flex items-center mb-2 text-ellipsis whitespace-nowrap max-w-[100%)] overflow-hidden' > - + {label === '__Community__' ? graphLabels.community : label} ({labelCounts[label]}) = ({ loading, mode, graphonly_entities, in return ( handleEntityClick(textId!, 'chatInfoView')} + htmlAttributes={{ + onClick: () => handleEntityClick(textId!, 'chatInfoView'), + }} className={loadingGraphView ? 'cursor-wait' : 'cursor-pointer'} > {text} @@ -146,4 +148,4 @@ const EntitiesInfo: FC = ({ loading, mode, graphonly_entities, in ); }; -export default EntitiesInfo; \ No newline at end of file +export default EntitiesInfo; diff --git a/frontend/src/components/ChatBot/ExpandedChatButtonContainer.tsx b/frontend/src/components/ChatBot/ExpandedChatButtonContainer.tsx index 44bddc805..b86ea04f3 100644 --- a/frontend/src/components/ChatBot/ExpandedChatButtonContainer.tsx +++ b/frontend/src/components/ChatBot/ExpandedChatButtonContainer.tsx @@ -1,37 +1,37 @@ import { TrashIconOutline, XMarkIconOutline } from '@neo4j-ndl/react/icons'; import ChatModeToggle from './ChatModeToggle'; -import { Box, IconButton } from '@neo4j-ndl/react'; +import { IconButton } from '@neo4j-ndl/react'; import { IconProps } from '../../types'; import { IconButtonWithToolTip } from '../UI/IconButtonToolTip'; import { tooltips } from '../../utils/Constants'; -import { memo, useState } from 'react'; +import { memo, useRef, useState } from 'react'; import { RiChatSettingsLine } from 'react-icons/ri'; const ExpandedChatButtonContainer: React.FC = ({ closeChatBot, deleteOnClick, messages }) => { - const [chatAnchor, setchatAnchor] = useState(null); + const chatAnchor = useRef(null); const [showChatModeOption, setshowChatModeOption] = useState(false); return (
            setshowChatModeOption(false)} - anchorPortal={true} - disableBackdrop={true} open={showChatModeOption} menuAnchor={chatAnchor} + isRoot={false} /> - - { - setchatAnchor(e.currentTarget); - setshowChatModeOption(true); - }} - clean - text='Chat mode' - placement='bottom' - label='Chat mode' - > - - +
            +
            + { + setshowChatModeOption(true); + }} + clean + text='Chat mode' + placement='bottom' + label='Chat mode' + > + + +
            = ({ closeChatBot, delete > - - + + - +
            ); }; diff --git a/frontend/src/components/ChatBot/MetricsCheckbox.tsx b/frontend/src/components/ChatBot/MetricsCheckbox.tsx new file mode 100644 index 000000000..31c1ab7f5 --- /dev/null +++ b/frontend/src/components/ChatBot/MetricsCheckbox.tsx @@ -0,0 +1,18 @@ +import { Checkbox } from '@neo4j-ndl/react'; + +function MetricsCheckbox({ + enableReference, + toggleReferenceVisibility, +}: { + enableReference: boolean; + toggleReferenceVisibility: React.DispatchWithoutAction; +}) { + return ( + + ); +} +export default MetricsCheckbox; diff --git a/frontend/src/components/ChatBot/MetricsTab.tsx b/frontend/src/components/ChatBot/MetricsTab.tsx index 55d37db4c..40e0b11fc 100644 --- a/frontend/src/components/ChatBot/MetricsTab.tsx +++ b/frontend/src/components/ChatBot/MetricsTab.tsx @@ -1,5 +1,5 @@ import { Banner, Box, DataGrid, DataGridComponents, Typography } from '@neo4j-ndl/react'; -import { memo, useMemo, useRef } from 'react'; +import { memo, useContext, useMemo, useRef } from 'react'; import { useReactTable, getCoreRowModel, @@ -9,6 +9,7 @@ import { getSortedRowModel, } from '@tanstack/react-table'; import { capitalize } from '../../utils/Utils'; +import { ThemeWrapperContext } from '../../context/ThemeWrapper'; function MetricsTab({ metricsLoading, metricDetails, @@ -17,14 +18,14 @@ function MetricsTab({ metricsLoading: boolean; metricDetails: | { - faithfulness: number; - answer_relevancy: number; + [key: string]: number | string; } | undefined; error: string; }) { - const columnHelper = createColumnHelper<{ metric: string; score: number }>(); + const columnHelper = createColumnHelper<{ metric: string; score: number | string }>(); const tableRef = useRef(null); + const { colorMode } = useContext(ThemeWrapperContext); const columns = useMemo( () => [ @@ -47,7 +48,7 @@ function MetricsTab({ header: () => Metric, footer: (info) => info.column.id, }), - columnHelper.accessor((row) => row.score, { + columnHelper.accessor((row) => row.score as number, { id: 'Score', cell: (info) => { return {info.getValue().toFixed(2)}; @@ -77,7 +78,9 @@ function MetricsTab({ return ( {error != undefined && error?.trim() != '' ? ( - {error} + + {error} + ) : ( , + Body: () => ( + + ), PaginationNumericButton: ({ isSelected, innerProps, ...restProps }) => { return ( )} diff --git a/frontend/src/components/ChatBot/MultiModeMetrics.tsx b/frontend/src/components/ChatBot/MultiModeMetrics.tsx index 4cf4aefd6..6744af10e 100644 --- a/frontend/src/components/ChatBot/MultiModeMetrics.tsx +++ b/frontend/src/components/ChatBot/MultiModeMetrics.tsx @@ -7,21 +7,24 @@ import { getSortedRowModel, } from '@tanstack/react-table'; import { capitalize } from '../../utils/Utils'; -import { useMemo, useRef } from 'react'; +import { useContext, useEffect, useMemo, useRef } from 'react'; import { Banner, Box, DataGrid, DataGridComponents, Typography } from '@neo4j-ndl/react'; import { multimodelmetric } from '../../types'; +import { ThemeWrapperContext } from '../../context/ThemeWrapper'; export default function MultiModeMetrics({ data, metricsLoading, error, + isWithAdditionalMetrics, }: { data: multimodelmetric[]; metricsLoading: boolean; error: string; + isWithAdditionalMetrics: boolean | null; }) { + const { colorMode } = useContext(ThemeWrapperContext); const tableRef = useRef(null); - const columnHelper = createColumnHelper(); const columns = useMemo( () => [ @@ -44,20 +47,41 @@ export default function MultiModeMetrics({ header: () => Mode, footer: (info) => info.column.id, }), - columnHelper.accessor((row) => row.answer_relevancy, { - id: 'Answer Relevancy', + columnHelper.accessor((row) => row.answer_relevancy as number, { + id: 'Relevancy', cell: (info) => { return {info.getValue().toFixed(2)}; }, - header: () => Answer Relevancy, + header: () => Relevancy, }), - columnHelper.accessor((row) => row.faithfulness, { + columnHelper.accessor((row) => row.faithfulness as number, { id: 'Score', cell: (info) => { return {info.getValue().toFixed(2)}; }, header: () => Faithfulness, }), + columnHelper.accessor((row) => row.context_entity_recall_score as number, { + id: 'Recall Score', + cell: (info) => { + return {info.getValue()?.toFixed(2)}; + }, + header: () => Context Score, + }), + columnHelper.accessor((row) => row.semantic_score as number, { + id: 'Semantic Score', + cell: (info) => { + return {info.getValue()?.toFixed(2)}; + }, + header: () => Semantic Score, + }), + columnHelper.accessor((row) => row.rouge_score as number, { + id: 'Rouge Score', + cell: (info) => { + return {info.getValue()?.toFixed(2)}; + }, + header: () => Rouge Score, + }), ], [] ); @@ -74,42 +98,63 @@ export default function MultiModeMetrics({ enableSorting: true, getSortedRowModel: getSortedRowModel(), }); + useEffect(() => { + if (isWithAdditionalMetrics === false) { + table.setColumnVisibility({ 'Recall Score': false, 'Semantic Score': false, 'Rouge Score': false }); + } else { + table.resetColumnVisibility(true); + } + }, [isWithAdditionalMetrics, table]); + return ( {error?.trim() != '' ? ( - {error} + + {error} + ) : ( - , - PaginationNumericButton: ({ isSelected, innerProps, ...restProps }) => { - return ( - + ( + - ); - }, - }} - /> + ), + PaginationNumericButton: ({ isSelected, innerProps, ...restProps }) => { + return ( + + ); + }, + }} + isKeyboardNavigable={false} + /> +
      )}
      ); diff --git a/frontend/src/components/ChatBot/SourcesInfo.tsx b/frontend/src/components/ChatBot/SourcesInfo.tsx index ddfe92a6e..ace69a07f 100644 --- a/frontend/src/components/ChatBot/SourcesInfo.tsx +++ b/frontend/src/components/ChatBot/SourcesInfo.tsx @@ -1,6 +1,6 @@ import { FC, useContext } from 'react'; import { Chunk, SourcesProps } from '../../types'; -import { Box, LoadingSpinner, TextLink, Typography } from '@neo4j-ndl/react'; +import { LoadingSpinner, TextLink, Typography } from '@neo4j-ndl/react'; import { DocumentTextIconOutline, GlobeAltIconOutline } from '@neo4j-ndl/react/icons'; import { getLogo, isAllowedHost, youtubeLinkValidation } from '../../utils/Utils'; import { ThemeWrapperContext } from '../../context/ThemeWrapper'; @@ -28,9 +28,9 @@ const SourcesInfo: FC = ({ loading, mode, chunks, sources }) => { return ( <> {loading ? ( - +
      - +
      ) : mode === 'entity search+vector' && uniqueChunks.length ? (
        {uniqueChunks @@ -65,7 +65,7 @@ const SourcesInfo: FC = ({ loading, mode, chunks, sources }) => { {isAllowedHost(link, ['wikipedia.org']) && (
        Wikipedia Logo - + = ({ loading, mode, chunks, sources }) => { <>
        - + = ({ loading, mode, chunks, sources }) => { !isAllowedHost(link, ['storage.googleapis.com', 'wikipedia.org', 'www.youtube.com']) && (
        - + {link}
        diff --git a/frontend/src/components/ChatBot/chatInfo.ts b/frontend/src/components/ChatBot/chatInfo.ts index 1a229dc70..c7e990ae7 100644 --- a/frontend/src/components/ChatBot/chatInfo.ts +++ b/frontend/src/components/ChatBot/chatInfo.ts @@ -37,4 +37,4 @@ export const handleGraphNodeClick = async ( setLoadingGraphView(false); } } -}; \ No newline at end of file +}; diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 8e8516666..3193a69bb 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -60,7 +60,6 @@ const Content: React.FC = ({ setIsSchema, showEnhancementDialog, toggleEnhancementDialog, - closeSettingModal, }) => { const { breakpoints } = tokens; const isTablet = useMediaQuery(`(min-width:${breakpoints.xs}) and (max-width: ${breakpoints.lg})`); @@ -105,7 +104,6 @@ const Content: React.FC = ({ filesData, setFilesData, setModel, - model, selectedNodes, selectedRels, setSelectedNodes, @@ -117,12 +115,13 @@ const Content: React.FC = ({ setProcessedCount, setchatModes, } = useFileContext(); - const [viewPoint, setViewPoint] = useState<'tableView' | 'showGraphView' | 'chatInfoView'|'neighborView'>('tableView'); + const [viewPoint, setViewPoint] = useState<'tableView' | 'showGraphView' | 'chatInfoView' | 'neighborView'>( + 'tableView' + ); const [showDeletePopUp, setshowDeletePopUp] = useState(false); const [deleteLoading, setdeleteLoading] = useState(false); const [searchParams] = useSearchParams(); - const { updateStatusForLargeFiles } = useServerSideEvent( (inMinutes, time, fileName) => { showNormalToast(`${fileName} will take approx ${time} ${inMinutes ? 'Min' : 'Sec'}`); @@ -133,11 +132,13 @@ const Content: React.FC = ({ } ); const childRef = useRef(null); - const incrementPage = () => { + const incrementPage = async () => { setCurrentPage((prev) => prev + 1); + await getChunks(documentName, currentPage + 1); }; - const decrementPage = () => { + const decrementPage = async () => { setCurrentPage((prev) => prev - 1); + await getChunks(documentName, currentPage - 1); }; useEffect(() => { if (!init && !searchParams.has('connectURL')) { @@ -165,23 +166,6 @@ const Content: React.FC = ({ setOpenConnection((prev) => ({ ...prev, openPopUp: true })); } }, []); - useEffect(() => { - if (currentPage >= 1) { - (async () => { - await getChunks(documentName, currentPage); - })(); - } - }, [currentPage, documentName]); - useEffect(() => { - setFilesData((prevfiles) => { - return prevfiles.map((curfile) => { - return { - ...curfile, - model: curfile.status === 'New' || curfile.status === 'Reprocess' ? model : curfile.model, - }; - }); - }); - }, [model]); useEffect(() => { if (afterFirstRender) { @@ -272,6 +256,15 @@ const Content: React.FC = ({ if (selectedOption?.value) { setModel(selectedOption?.value); } + setFilesData((prevfiles) => { + return prevfiles.map((curfile) => { + return { + ...curfile, + model: + curfile.status === 'New' || curfile.status === 'Reprocess' ? selectedOption?.value ?? '' : curfile.model, + }; + }); + }); }; const getChunks = async (name: string, pageNo: number) => { toggleChunksLoading(); @@ -814,11 +807,7 @@ const Content: React.FC = ({ > )} {showEnhancementDialog && ( - + )}
        @@ -840,24 +829,28 @@ const Content: React.FC = ({ isGdsActive={isGdsActive} uri={userCredentials && userCredentials?.uri} /> -
        - {!isSchema ? ( - - ) : selectedNodes.length || selectedRels.length ? ( - - ) : ( - - )} - {isSchema ? ( - - {(!selectedNodes.length || !selectedNodes.length) && 'Empty'} Graph Schema configured - {selectedNodes.length || selectedRels.length - ? `(${selectedNodes.length} Labels + ${selectedRels.length} Rel Types)` - : ''} - - ) : ( - No Graph Schema configured - )} +
        +
        + {!isSchema ? ( + + ) : selectedNodes.length || selectedRels.length ? ( + + ) : ( + + )} +
        +
        + {isSchema ? ( + + {(!selectedNodes.length || !selectedNodes.length) && 'Empty'} Graph Schema configured + {selectedNodes.length || selectedRels.length + ? `(${selectedNodes.length} Labels + ${selectedRels.length} Rel Types)` + : ''} + + ) : ( + No Graph Schema configured + )} +
        @@ -909,7 +902,7 @@ const Content: React.FC = ({ setTotalPageCount(null); } setCurrentPage(1); - // await getChunks(name, 1); + await getChunks(name, 1); } }} ref={childRef} @@ -993,4 +986,4 @@ const Content: React.FC = ({ ); }; -export default Content; \ No newline at end of file +export default Content; diff --git a/frontend/src/components/DataSources/AWS/S3Modal.tsx b/frontend/src/components/DataSources/AWS/S3Modal.tsx index c23b94a3b..51144c930 100644 --- a/frontend/src/components/DataSources/AWS/S3Modal.tsx +++ b/frontend/src/components/DataSources/AWS/S3Modal.tsx @@ -153,55 +153,61 @@ const S3Modal: React.FC = ({ hideModal, open }) => {
        setValid(validation(bucketUrl) && isFocused), + onKeyDown: handleKeyDown, + 'aria-label': 'Bucket URL', + placeholder: 's3://data.neo4j.com/pdf/', + }} value={bucketUrl} - disabled={false} + isDisabled={false} label='Bucket URL' - aria-label='Bucket URL' - placeholder='s3://data.neo4j.com/pdf/' - autoFocus - fluid - required + isFluid={true} + isRequired={true} errorText={!isValid && isFocused && 'Please Fill The Valid URL'} - onBlur={() => setValid(validation(bucketUrl) && isFocused)} onChange={(e) => { setisFocused(true); setBucketUrl(e.target.value); }} - onKeyDown={handleKeyDown} />
        { setAccessKey(e.target.value); }} - onKeyDown={handleKeyDown} /> { setSecretKey(e.target.value); }} - onKeyDown={handleKeyDown} />
        diff --git a/frontend/src/components/DataSources/GCS/GCSModal.tsx b/frontend/src/components/DataSources/GCS/GCSModal.tsx index a68faeb97..8893c4f70 100644 --- a/frontend/src/components/DataSources/GCS/GCSModal.tsx +++ b/frontend/src/components/DataSources/GCS/GCSModal.tsx @@ -1,5 +1,5 @@ import { TextInput } from '@neo4j-ndl/react'; -import { useCallback, useEffect, useState } from 'react'; +import { useCallback, useState } from 'react'; import { useCredentials } from '../../../context/UserCredentials'; import { useFileContext } from '../../../context/UsersFiles'; import { urlScanAPI } from '../../../services/URLScan'; @@ -41,17 +41,6 @@ const GCSModal: React.FC = ({ hideModal, open, openGCSModal }) => setprojectId(''); }; - useEffect(() => { - if (status != 'unknown') { - setTimeout(() => { - setStatusMessage(''); - setStatus('unknown'); - reset(); - hideModal(); - }, 5000); - } - }, []); - const googleLogin = useGoogleLogin({ onSuccess: async (codeResponse) => { try { @@ -195,48 +184,55 @@ const GCSModal: React.FC = ({ hideModal, open, openGCSModal }) =>
        { setprojectId(e.target.value); }} - onKeyDown={handleKeyPress} > { setbucketName(e.target.value); }} - onKeyDown={handleKeyPress} /> { setFolderName(e.target.value); }} - onKeyDown={handleKeyPress} />
        diff --git a/frontend/src/components/DataSources/Local/DropZone.tsx b/frontend/src/components/DataSources/Local/DropZone.tsx index bddbb65f0..38a6dd1d9 100644 --- a/frontend/src/components/DataSources/Local/DropZone.tsx +++ b/frontend/src/components/DataSources/Local/DropZone.tsx @@ -1,5 +1,5 @@ import { Dropzone, Flex, Typography } from '@neo4j-ndl/react'; -import { useState, useEffect, FunctionComponent } from 'react'; +import { useState, FunctionComponent, useEffect } from 'react'; import Loader from '../../../utils/Loader'; import { v4 as uuidv4 } from 'uuid'; import { useCredentials } from '../../../context/UserCredentials'; @@ -68,7 +68,6 @@ const DropZone: FunctionComponent = () => { setFilesData(copiedFilesData); } }; - useEffect(() => { if (selectedFiles.length > 0) { for (let index = 0; index < selectedFiles.length; index++) { @@ -79,6 +78,7 @@ const DropZone: FunctionComponent = () => { } } }, [selectedFiles]); + const uploadFileInChunks = (file: File) => { const totalChunks = Math.ceil(file.size / chunkSize); const chunkProgressIncrement = 100 / totalChunks; @@ -127,7 +127,7 @@ const DropZone: FunctionComponent = () => { if (curfile.name == file.name) { return { ...curfile, - uploadprogess: chunkNumber * chunkProgressIncrement, + uploadProgress: chunkNumber * chunkProgressIncrement, }; } return curfile; @@ -139,7 +139,7 @@ const DropZone: FunctionComponent = () => { if (curfile.name == file.name) { return { ...curfile, - uploadprogess: chunkNumber * chunkProgressIncrement, + uploadProgress: chunkNumber * chunkProgressIncrement, }; } return curfile; @@ -179,7 +179,7 @@ const DropZone: FunctionComponent = () => { return { ...curfile, status: 'New', - uploadprogess: 100, + uploadProgress: 100, }; } return curfile; diff --git a/frontend/src/components/DataSources/Local/DropZoneForSmallLayouts.tsx b/frontend/src/components/DataSources/Local/DropZoneForSmallLayouts.tsx index d7fb1e56d..1b27f4eb7 100644 --- a/frontend/src/components/DataSources/Local/DropZoneForSmallLayouts.tsx +++ b/frontend/src/components/DataSources/Local/DropZoneForSmallLayouts.tsx @@ -15,18 +15,7 @@ export default function DropZoneForSmallLayouts() { const [isLoading, setIsLoading] = useState(false); const [isClicked, setIsClicked] = useState(false); const { userCredentials } = useCredentials(); - const [selectedFiles, setSelectedFiles] = useState([]); - useEffect(() => { - if (selectedFiles.length > 0) { - for (let index = 0; index < selectedFiles.length; index++) { - const file = selectedFiles[index]; - if (filesData[index]?.status == 'None' && isClicked) { - uploadFileInChunks(file); - } - } - } - }, [selectedFiles]); const uploadFileInChunks = (file: File) => { const totalChunks = Math.ceil(file.size / chunkSize); @@ -214,11 +203,21 @@ export default function DropZoneForSmallLayouts() { setFilesData(copiedFilesData); } }; + useEffect(() => { + if (selectedFiles.length > 0) { + for (let index = 0; index < selectedFiles.length; index++) { + const file = selectedFiles[index]; + if (filesData[index]?.status == 'None' && isClicked) { + uploadFileInChunks(file); + } + } + } + }, [selectedFiles]); return ( <>
        - {isLoading ? : } + {isLoading ? : }
        ); diff --git a/frontend/src/components/Dropdown.tsx b/frontend/src/components/Dropdown.tsx index 3aae5aa6f..a3ebd0d5a 100644 --- a/frontend/src/components/Dropdown.tsx +++ b/frontend/src/components/Dropdown.tsx @@ -1,4 +1,4 @@ -import { Dropdown, Tip, useMediaQuery } from '@neo4j-ndl/react'; +import { Tooltip, useMediaQuery, Select } from '@neo4j-ndl/react'; import { OptionType, ReusableDropdownProps } from '../types'; import { memo, useMemo } from 'react'; import { capitalize, capitalizeWithUnderscore } from '../utils/Utils'; @@ -22,9 +22,8 @@ const DropdownComponent: React.FC = ({ return ( <>
        - LLM Model used for Extraction & Chat
        } selectProps={{ @@ -36,12 +35,12 @@ const DropdownComponent: React.FC = ({ const isModelSupported = !isProdEnv || prodllms?.includes(value); return { label: !isModelSupported ? ( - - + + {label} - - Available In Development Version - + + Available In Development Version + ) : ( {label} ), @@ -58,7 +57,10 @@ const DropdownComponent: React.FC = ({ value: value, }} size='medium' - fluid + isFluid + htmlAttributes={{ + 'aria-label': 'A selection dropdown', + }} /> {children}
        diff --git a/frontend/src/components/FileTable.tsx b/frontend/src/components/FileTable.tsx index 42b82572a..ddbaebbac 100644 --- a/frontend/src/components/FileTable.tsx +++ b/frontend/src/components/FileTable.tsx @@ -103,15 +103,15 @@ const FileTable = forwardRef((props, ref) => { .includes('Processing'); return ( ); }, @@ -161,11 +161,13 @@ const FileTable = forwardRef((props, ref) => { if (info.getValue() != 'Processing') { return (
        - - {info.getValue()} +
        + +
        +
        {info.getValue()}
        {(info.getValue() === 'Completed' || info.getValue() === 'Failed' || info.getValue() === 'Cancelled') && !isReadOnlyUser && ( @@ -177,7 +179,7 @@ const FileTable = forwardRef((props, ref) => { clean onClick={() => onRetry(info?.row?.id as string)} > - + )} @@ -185,16 +187,22 @@ const FileTable = forwardRef((props, ref) => { ); } else if (info.getValue() === 'Processing' && info.row.original.processingProgress === undefined) { return ( -
        - - Processing +
        +
        + +
        +
        + Processing +
        { cancelHandler( info.row.original.name as string, @@ -223,10 +231,12 @@ const FileTable = forwardRef((props, ref) => {
        { cancelHandler( info.row.original.name as string, @@ -242,9 +252,11 @@ const FileTable = forwardRef((props, ref) => { ); } return ( -
        - - {info.getValue()} +
        +
        + +
        +
        {info.getValue()}
        ); }, @@ -304,7 +316,7 @@ const FileTable = forwardRef((props, ref) => { }, }, ], - defaultSortingActions: false, + hasDefaultSortingActions: false, }, }, }), @@ -313,26 +325,32 @@ const FileTable = forwardRef((props, ref) => { cell: (info: CellContext) => { if (parseInt(info.getValue()) === 100 || info.row.original?.status === 'New') { return ( - - - Uploaded - +
        + + + + Uploaded +
        ); } else if (info.row.original?.status === 'Uploading') { return ; } else if (info.row.original?.status === 'Failed') { return ( - - - NA - +
        + + + + NA +
        ); } return ( - - - Uploaded - +
        + + + + Uploaded +
        ); }, header: () => Upload Status, @@ -355,7 +373,7 @@ const FileTable = forwardRef((props, ref) => { return ( - + {info.row.original.fileSource} @@ -400,7 +418,7 @@ const FileTable = forwardRef((props, ref) => { }; }), ], - defaultSortingActions: false, + hasDefaultSortingActions: false, }, }, }), @@ -443,7 +461,7 @@ const FileTable = forwardRef((props, ref) => { }; }), ], - defaultSortingActions: false, + hasDefaultSortingActions: false, }, }, }), @@ -484,7 +502,7 @@ const FileTable = forwardRef((props, ref) => { }; }), ], - defaultSortingActions: false, + hasDefaultSortingActions: false, }, }, }), @@ -513,7 +531,7 @@ const FileTable = forwardRef((props, ref) => { clean onClick={() => onInspect(info?.row?.original?.name as string)} > - + ((props, ref) => { label='chunktextaction' text='View Chunks' size='large' - disabled={info.getValue() === 'Uploading'} + disabled={info.getValue() === 'Uploading' || info.getValue() === 'New'} > - + ), - size: 300, + maxSize: 300, minSize: 180, header: () => Actions, footer: (info) => info.column.id, @@ -927,7 +945,7 @@ const FileTable = forwardRef((props, ref) => { tableInstance={table} styling={{ borderStyle: 'all-sides', - zebraStriping: true, + hasZebraStriping: true, headerStyle: 'clean', }} isLoading={isLoading} @@ -935,7 +953,13 @@ const FileTable = forwardRef((props, ref) => { className: classNameCheck, }} components={{ - Body: (props) => , + Body: () => ( + + ), PaginationNumericButton: ({ isSelected, innerProps, ...restProps }) => { return ( ((props, ref) => { ); }, }} + isKeyboardNavigable={false} />
        @@ -962,4 +987,4 @@ const FileTable = forwardRef((props, ref) => { ); }); -export default FileTable; \ No newline at end of file +export default FileTable; diff --git a/frontend/src/components/Graph/CheckboxSelection.tsx b/frontend/src/components/Graph/CheckboxSelection.tsx index b8caf7484..220b138f7 100644 --- a/frontend/src/components/Graph/CheckboxSelection.tsx +++ b/frontend/src/components/Graph/CheckboxSelection.tsx @@ -15,25 +15,25 @@ const CheckboxSelection: React.FC = ({
        {isDocChunk && ( handleChange('DocumentChunk')} /> )} {isEntity && ( handleChange('Entities')} /> )} {isCommunity && ( handleChange('Communities')} /> )} diff --git a/frontend/src/components/Graph/GraphPropertiesTable.tsx b/frontend/src/components/Graph/GraphPropertiesTable.tsx index fa270455b..753c200fb 100644 --- a/frontend/src/components/Graph/GraphPropertiesTable.tsx +++ b/frontend/src/components/Graph/GraphPropertiesTable.tsx @@ -16,7 +16,9 @@ const GraphPropertiesTable = ({ propertiesWithTypes }: GraphPropertiesTableProps
        {key} diff --git a/frontend/src/components/Graph/GraphViewModal.tsx b/frontend/src/components/Graph/GraphViewModal.tsx index ac35a93ae..4fe1f52f5 100644 --- a/frontend/src/components/Graph/GraphViewModal.tsx +++ b/frontend/src/components/Graph/GraphViewModal.tsx @@ -1,4 +1,4 @@ -import { Banner, Dialog, Flex, IconButtonArray, LoadingSpinner, useDebounce } from '@neo4j-ndl/react'; +import { Banner, Dialog, Flex, IconButtonArray, LoadingSpinner, useDebounceValue } from '@neo4j-ndl/react'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { BasicNode, @@ -53,7 +53,7 @@ const GraphViewModal: React.FunctionComponent = ({ const [scheme, setScheme] = useState({}); const [newScheme, setNewScheme] = useState({}); const [searchQuery, setSearchQuery] = useState(''); - const debouncedQuery = useDebounce(searchQuery, 300); + const [debouncedQuery] = useDebounceValue(searchQuery, 300); const [graphType, setGraphType] = useState([]); const [disableRefresh, setDisableRefresh] = useState(false); const [selected, setSelected] = useState<{ type: EntityType; id: string } | undefined>(undefined); @@ -339,12 +339,14 @@ const GraphViewModal: React.FunctionComponent = ({ id: 'default-menu', }} size='unset' - open={open} - aria-labelledby='form-dialog-title' - disableCloseButton={false} + isOpen={open} + hasDisabledCloseButton={false} onClose={onClose} + htmlAttributes={{ + 'aria-labelledby': 'form-dialog-title', + }} > - + {headerTitle} {checkBoxView && ( @@ -365,15 +367,15 @@ const GraphViewModal: React.FunctionComponent = ({
        ) : status !== 'unknown' ? (
        - +
        ) : nodes.length === 0 && relationships.length === 0 && graphType.length !== 0 ? (
        - +
        ) : graphType.length === 0 && checkBoxView ? (
        - +
        ) : ( <> @@ -390,7 +392,7 @@ const GraphViewModal: React.FunctionComponent = ({ }} nvlCallbacks={nvlCallbacks} /> - + {viewPoint !== 'chatInfoView' && ( = ({ placement='left' disabled={disableRefresh} > - + )} - + - + = ({ onClick={handleZoomToFit} placement='left' > - +
        @@ -445,4 +447,4 @@ const GraphViewModal: React.FunctionComponent = ({ ); }; -export default GraphViewModal; \ No newline at end of file +export default GraphViewModal; diff --git a/frontend/src/components/Graph/ResultOverview.tsx b/frontend/src/components/Graph/ResultOverview.tsx index 142c9fabc..6c3de167a 100644 --- a/frontend/src/components/Graph/ResultOverview.tsx +++ b/frontend/src/components/Graph/ResultOverview.tsx @@ -114,17 +114,25 @@ const ResultOverview: React.FunctionComponent = ({ {graphLabels.resultOverview}
        { setSearchQuery(e.target.value); }} - placeholder='Search On Node Properties' - fluid={true} - leftIcon={ - - + isFluid={true} + leftElement={ + + } /> diff --git a/frontend/src/components/Layout/DrawerChatbot.tsx b/frontend/src/components/Layout/DrawerChatbot.tsx index 3150e96a5..074c4ff78 100644 --- a/frontend/src/components/Layout/DrawerChatbot.tsx +++ b/frontend/src/components/Layout/DrawerChatbot.tsx @@ -11,7 +11,7 @@ const DrawerChatbot: React.FC = ({ isExpanded, clearHistoryD }; return (
        - + = ({ return (
        - + {!isReadOnlyUser ? ( - + {alertState.showAlert && ( = ({ }`} > {process.env.VITE_ENV != 'PROD' && ( - + {!isBackendConnected ? : } @@ -211,7 +211,7 @@ const DrawerDropzone: React.FC = ({
        ) : ( - + This user account does not have permission to access or manage data sources. diff --git a/frontend/src/components/Layout/Header.tsx b/frontend/src/components/Layout/Header.tsx index 752c31660..a47cbf505 100644 --- a/frontend/src/components/Layout/Header.tsx +++ b/frontend/src/components/Layout/Header.tsx @@ -39,7 +39,7 @@ function Header() { aria-label='main navigation' >
        - + void; - openSettingsDialog: () => void; -}) { +export default function PageLayout() { const largedesktops = useMediaQuery(`(min-width:1440px )`); const { userCredentials, connectionStatus } = useCredentials(); const [isLeftExpanded, setIsLeftExpanded] = useState(Boolean(largedesktops)); @@ -46,18 +38,34 @@ export default function PageLayoutNew({ } }; - const { messages, setClearHistoryData, clearHistoryData } = useMessageContext(); + const { messages, setClearHistoryData, clearHistoryData, setMessages } = useMessageContext(); const { isSchema, setIsSchema, setShowTextFromSchemaDialog, showTextFromSchemaDialog } = useFileContext(); - + const { cancel } = useSpeechSynthesis(); const deleteOnClick = async () => { try { setClearHistoryData(true); + cancel(); const response = await clearChatAPI( userCredentials as UserCredentials, sessionStorage.getItem('session_id') ?? '' ); if (response.data.status === 'Success') { - setClearHistoryData(false); + const date = new Date(); + + setMessages([ + { + datetime: `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`, + id: 2, + modes: { + 'graph+vector+fulltext': { + message: + ' Welcome to the Neo4j Knowledge Graph Chat. You can ask questions related to documents which have been completely processed.', + }, + }, + user: 'chatbot', + currentMode: 'graph+vector+fulltext', + }, + ]); } } catch (error) { console.log(error); @@ -86,31 +94,17 @@ export default function PageLayoutNew({ /> { setShowTextFromSchemaDialog({ triggeredFrom: '', show: false }); switch (showTextFromSchemaDialog.triggeredFrom) { case 'enhancementtab': toggleEnhancementDialog(); break; - case 'schemadialog': - openSettingsDialog(); - break; default: break; } }} > - { - setShowTextFromSchemaDialog({ triggeredFrom: 'schemadialog', show: true }); - }} - open={isSettingPanelExpanded} - onClose={closeSettingModal} - settingView='headerView' - isSchema={isSchema} - setIsSchema={setIsSchema} - /> setShowChatBot(true)} isLeftExpanded={isLeftExpanded} @@ -123,7 +117,6 @@ export default function PageLayoutNew({ setIsSchema={setIsSchema} showEnhancementDialog={showEnhancementDialog} toggleEnhancementDialog={toggleEnhancementDialog} - closeSettingModal={closeSettingModal} /> {showDrawerChatbot && ( = ({ position, @@ -43,31 +44,11 @@ const SideNav: React.FC = ({ const [isChatModalOpen, setIsChatModalOpen] = useState(false); const [isFullScreen, setIsFullScreen] = useState(false); const { setMessages } = useMessageContext(); - const [chatModeAnchor, setchatModeAnchor] = useState(null); const [showChatMode, setshowChatMode] = useState(false); const largedesktops = useMediaQuery(`(min-width:1440px )`); const { connectionStatus, isReadOnlyUser } = useCredentials(); const downloadLinkRef = useRef(null); - - const date = new Date(); - useEffect(() => { - if (clearHistoryData) { - setMessages([ - { - datetime: `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`, - id: 2, - modes: { - 'graph+vector+fulltext': { - message: - ' Welcome to the Neo4j Knowledge Graph Chat. You can ask questions related to documents which have been completely processed.', - }, - }, - user: 'chatbot', - currentMode: 'graph+vector+fulltext', - }, - ]); - } - }, [clearHistoryData]); + const anchorMenuRef = useRef(null); const handleExpandClick = () => { setIsChatModalOpen(true); @@ -98,32 +79,38 @@ const SideNav: React.FC = ({ return (
        - + {isExpanded && largedesktops && ( : } + htmlAttributes={{ onClick: handleClick }} + icon={ + position === 'left' ? ( + + ) : ( + + ) + } /> )} {!isExpanded && position === 'left' && largedesktops && ( - - + + + } /> )} {position === 'right' && !isExpanded && ( - - + + + } /> )} @@ -131,108 +118,117 @@ const SideNav: React.FC = ({ {!largedesktops && position === 'left' && !isReadOnlyUser && ( + - + } /> )} {!largedesktops && APP_SOURCES.includes('gcs') && position === 'left' && !isReadOnlyUser && ( + - + } /> )} {!largedesktops && APP_SOURCES.includes('s3') && position === 'left' && !isReadOnlyUser && ( + - + } /> )} {!largedesktops && APP_SOURCES.includes('web') && position === 'left' && !isReadOnlyUser && ( + - + } > )} {position === 'right' && isExpanded && ( <> - + - - - - {tooltips.clearChat} + + + + {tooltips.clearChat} } /> - - + + - + - - {tooltips.maximise} + + {tooltips.maximise} } /> - - + + { - downloadClickHandler( - { conversation: messages }, - downloadLinkRef, - 'graph-builder-conversation.json' - ); + htmlAttributes={{ + onClick: () => { + downloadClickHandler( + { conversation: messages }, + downloadLinkRef, + 'graph-builder-conversation.json' + ); + }, }} icon={ <> - + - - + + Download Conversation "" - + } /> - + {!isChatModalOpen && ( { - setchatModeAnchor(e.currentTarget); - setshowChatMode(true); - }} + ref={anchorMenuRef} icon={ <> - + { + setshowChatMode(true); + }} + size='small' + placement='left' + clean + label='Chat mode' + text='Chat mode' + > setshowChatMode(false)} - menuAnchor={chatModeAnchor} - disableBackdrop={true} - anchorPortal={true} + closeHandler={() => { + setshowChatMode(false); + }} + menuAnchor={anchorMenuRef} + isRoot={false} > } @@ -249,11 +245,11 @@ const SideNav: React.FC = ({ id: 'Chatbot-popup', className: 'n-p-token-4 n-rounded-lg h-[90%]', }} - open={isChatModalOpen} + isOpen={isChatModalOpen} size='unset' - disableCloseButton={true} + hasDisabledCloseButton={true} > - + { + const { breakpoints } = tokens; + const isTablet = useMediaQuery(`(min-width:${breakpoints.xs}) and (max-width: ${breakpoints.lg})`); const sortedChunksData = useMemo(() => { return chunks.sort((a, b) => a.position - b.position); }, [chunks]); + return ( - - Text Chunks + + +
        + +
        + Text Chunks + + These text chunks are extracted to build a knowledge graph and enable accurate information retrieval using + a different retrival strategies + +
        +
        + {!chunksLoading && totalPageCount != null && totalPageCount > 0 && ( +
        + Total Pages: {totalPageCount} +
        + )} +
        {chunksLoading ? ( ) : ( -
          +
            {sortedChunksData.map((c, idx) => ( -
          1. - +
          2. + Position : {c.position} @@ -57,10 +82,10 @@ const ChunkPopUp = ({ {totalPageCount != null && totalPageCount > 1 && ( - + - + diff --git a/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx b/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx index 76df732a4..934a38f76 100644 --- a/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx +++ b/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx @@ -1,4 +1,4 @@ -import { Button, Dialog, TextInput, Dropdown, Banner, Dropzone, Typography, TextLink, Flex } from '@neo4j-ndl/react'; +import { Button, Dialog, TextInput, Select, Banner, Dropzone, Typography, TextLink, Flex } from '@neo4j-ndl/react'; import React, { useCallback, useEffect, useMemo, useState, useRef } from 'react'; import connectAPI from '../../../services/ConnectAPI'; import { useCredentials } from '../../../context/UserCredentials'; @@ -311,18 +311,20 @@ export default function ConnectionModal({ <> { setOpenConnection((prev) => ({ ...prev, openPopUp: false })); setMessage({ type: 'unknown', content: '' }); }} - disableCloseButton={vectorIndexLoading} + hasDisabledCloseButton={vectorIndexLoading} + htmlAttributes={{ + 'aria-labelledby': 'form-dialog-title', + }} > - Connect to Neo4j + Connect to Neo4j - + Don't have a Neo4j instance? Start for free today @@ -330,17 +332,19 @@ export default function ConnectionModal({ (vectorIndexLoading ? ( ) : ( ))}
            @@ -363,87 +367,97 @@ export default function ConnectionModal({ />
            - newValue && setProtocol(newValue.value), options: protocols.map((option) => ({ label: option, value: option })), value: { label: protocol, value: protocol }, }} className='w-1/4 inline-block' - fluid + isFluid + htmlAttributes={{ + id: 'protocol', + }} />
            handleHostPasteChange(e), + onKeyDown: (e) => handleKeyPress(e, databaseRef), + 'aria-label': 'Connection URI', + }} value={URI} - disabled={false} + isDisabled={false} label='URI' - autoFocus - fluid + isFluid={true} onChange={(e) => setURI(e.target.value)} - onPaste={(e) => handleHostPasteChange(e)} - aria-label='Connection URI' - onKeyDown={(e) => handleKeyPress(e, databaseRef)} />
            setDatabase(e.target.value)} className='w-full' - onKeyDown={handleKeyPress} />
            setUsername(e.target.value)} - onKeyDown={handleKeyPress} />
            setPassword(e.target.value)} - onKeyDown={handleKeyPress} />
            ); -} \ No newline at end of file +} diff --git a/frontend/src/components/Popups/ConnectionModal/VectorIndexMisMatchAlert.tsx b/frontend/src/components/Popups/ConnectionModal/VectorIndexMisMatchAlert.tsx index 3c2965f44..79c472aeb 100644 --- a/frontend/src/components/Popups/ConnectionModal/VectorIndexMisMatchAlert.tsx +++ b/frontend/src/components/Popups/ConnectionModal/VectorIndexMisMatchAlert.tsx @@ -33,7 +33,7 @@ To proceed, please choose one of the following options: : ''} - +
            {isVectorIndexAlreadyExists ? 'Re-Create Vector Index' : 'Create Vector Index'} - +
            ); } diff --git a/frontend/src/components/Popups/DeletePopUp/DeletePopUp.tsx b/frontend/src/components/Popups/DeletePopUp/DeletePopUp.tsx index cbe69c492..e3604e70c 100644 --- a/frontend/src/components/Popups/DeletePopUp/DeletePopUp.tsx +++ b/frontend/src/components/Popups/DeletePopUp/DeletePopUp.tsx @@ -25,14 +25,14 @@ function DeletePopUp({ no_of_files > 1 ? 'Nodes' : 'Node' } from the graph database? `; return ( - +
            {message}
            {view === 'contentView' && (
            { if (e.target.checked) { setDeleteEntities(true); @@ -45,10 +45,10 @@ function DeletePopUp({ )} - - diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx index 330f5f657..d59b46e21 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; import { getDuplicateNodes } from '../../../../services/GetDuplicateNodes'; import { useCredentials } from '../../../../context/UserCredentials'; import { dupNodes, selectedDuplicateNodes, UserCredentials } from '../../../../types'; @@ -30,6 +30,7 @@ import mergeDuplicateNodes from '../../../../services/MergeDuplicateEntities'; import { tokens } from '@neo4j-ndl/base'; import GraphViewModal from '../../../Graph/GraphViewModal'; import { handleGraphNodeClick } from '../../../ChatBot/chatInfo'; +import { ThemeWrapperContext } from '../../../../context/ThemeWrapper'; export default function DeduplicationTab() { const { breakpoints } = tokens; @@ -46,6 +47,8 @@ export default function DeduplicationTab() { const [openGraphView, setOpenGraphView] = useState(false); const [viewPoint, setViewPoint] = useState(''); const [nodesCount, setNodesCount] = useState(0); + const { colorMode } = useContext(ThemeWrapperContext); + const fetchDuplicateNodes = useCallback(async () => { try { setLoading(true); @@ -66,10 +69,13 @@ export default function DeduplicationTab() { console.log(error); } }, [userCredentials]); + useEffect(() => { - (async () => { - await fetchDuplicateNodes(); - })(); + if (userCredentials != null) { + (async () => { + await fetchDuplicateNodes(); + })(); + } }, [userCredentials]); const clickHandler = async () => { @@ -127,8 +133,8 @@ export default function DeduplicationTab() { header: ({ table }: { table: Table }) => { return ( ); @@ -137,10 +143,10 @@ export default function DeduplicationTab() { return (
            ); @@ -154,8 +160,10 @@ export default function DeduplicationTab() {
            handleDuplicateNodeClick(info.row.id, 'chatInfoView')} - title={info.getValue()} + htmlAttributes={{ + onClick: () => handleDuplicateNodeClick(info.row.id, 'chatInfoView'), + title: info.getValue(), + }} > {info.getValue()} @@ -179,7 +187,7 @@ export default function DeduplicationTab() { onRemove={() => { onRemove(info.row.original.e.elementId, s.elementId); }} - removeable={true} + isRemovable={true} type='default' size={isTablet ? 'small' : 'medium'} > @@ -286,7 +294,7 @@ export default function DeduplicationTab() { tableInstance={table} styling={{ borderStyle: 'all-sides', - zebraStriping: true, + hasZebraStriping: true, headerStyle: 'clean', }} rootProps={{ @@ -294,7 +302,13 @@ export default function DeduplicationTab() { }} isLoading={isLoading} components={{ - Body: (props) => , + Body: () => ( + + ), PaginationNumericButton: ({ isSelected, innerProps, ...restProps }) => { return ( ); -} \ No newline at end of file +} diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx index 6d4daae10..1f6bdb347 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx @@ -1,5 +1,5 @@ import { Checkbox, DataGrid, DataGridComponents, Flex, TextLink, Typography, useMediaQuery } from '@neo4j-ndl/react'; -import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; import { UserCredentials, orphanNodeProps } from '../../../../types'; import { getOrphanNodes } from '../../../../services/GetOrphanNodes'; import { useCredentials } from '../../../../context/UserCredentials'; @@ -21,6 +21,7 @@ import DeletePopUp from '../../DeletePopUp/DeletePopUp'; import { tokens } from '@neo4j-ndl/base'; import GraphViewModal from '../../../Graph/GraphViewModal'; import { handleGraphNodeClick } from '../../../ChatBot/chatInfo'; +import { ThemeWrapperContext } from '../../../../context/ThemeWrapper'; export default function DeletePopUpForOrphanNodes({ deleteHandler, loading, @@ -41,6 +42,7 @@ export default function DeletePopUpForOrphanNodes({ const [neoRels, setNeoRels] = useState([]); const [openGraphView, setOpenGraphView] = useState(false); const [viewPoint, setViewPoint] = useState(''); + const { colorMode } = useContext(ThemeWrapperContext); const fetchOrphanNodes = useCallback(async () => { try { @@ -62,9 +64,11 @@ export default function DeletePopUpForOrphanNodes({ }, [userCredentials]); useEffect(() => { - (async () => { - await fetchOrphanNodes(); - })(); + if (userCredentials != null) { + (async () => { + await fetchOrphanNodes(); + })(); + } return () => { setOrphanNodes([]); setTotalOrphanNodes(0); @@ -91,8 +95,8 @@ export default function DeletePopUpForOrphanNodes({ header: ({ table }: { table: Table }) => { return ( ); @@ -101,10 +105,10 @@ export default function DeletePopUpForOrphanNodes({ return (
            ); @@ -118,8 +122,10 @@ export default function DeletePopUpForOrphanNodes({
            handleOrphanNodeClick(info.row.id, 'chatInfoView')} - title={info.getValue()} + htmlAttributes={{ + onClick: () => handleOrphanNodeClick(info.row.id, 'chatInfoView'), + title: info.getValue(), + }} > {info.getValue()} @@ -254,7 +260,7 @@ export default function DeletePopUpForOrphanNodes({ tableInstance={table} styling={{ borderStyle: 'all-sides', - zebraStriping: true, + hasZebraStriping: true, headerStyle: 'clean', }} rootProps={{ @@ -262,7 +268,13 @@ export default function DeletePopUpForOrphanNodes({ }} isLoading={isLoading} components={{ - Body: (props) => , + Body: () => ( + + ), PaginationNumericButton: ({ isSelected, innerProps, ...restProps }) => { return ( ); -} \ No newline at end of file +} diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/EnitityExtraction/EntityExtractionSetting.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/EnitityExtraction/EntityExtractionSetting.tsx index 3ab5b48bd..9743e5b14 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/EnitityExtraction/EntityExtractionSetting.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/EnitityExtraction/EntityExtractionSetting.tsx @@ -1,13 +1,12 @@ -import { MouseEventHandler, useCallback, useEffect, useState } from 'react'; +import { MouseEventHandler, useCallback, useEffect, useMemo, useState } from 'react'; import ButtonWithToolTip from '../../../UI/ButtonWithToolTip'; -import { appLabels, buttonCaptions, tooltips } from '../../../../utils/Constants'; -import { Dropdown, Flex, Typography, useMediaQuery } from '@neo4j-ndl/react'; +import { appLabels, buttonCaptions, getDefaultSchemaExamples, tooltips } from '../../../../utils/Constants'; +import { Select, Flex, Typography, useMediaQuery } from '@neo4j-ndl/react'; import { useCredentials } from '../../../../context/UserCredentials'; import { useFileContext } from '../../../../context/UsersFiles'; import { OnChangeValue, ActionMeta } from 'react-select'; import { OptionType, schema, UserCredentials } from '../../../../types'; import { getNodeLabelsAndRelTypes } from '../../../../services/GetNodeLabelsRelTypes'; -import schemaExamples from '../../../../assets/schemas.json'; import { tokens } from '@neo4j-ndl/base'; import { showNormalToast } from '../../../../utils/toasts'; @@ -149,22 +148,8 @@ export default function EntityExtractionSetting({ }; const [nodeLabelOptions, setnodeLabelOptions] = useState([]); const [relationshipTypeOptions, setrelationshipTypeOptions] = useState([]); - const [defaultExamples, setdefaultExamples] = useState([]); + const defaultExamples = useMemo(() => getDefaultSchemaExamples(), []); - useEffect(() => { - const parsedData = schemaExamples.reduce((accu: OptionType[], example) => { - const examplevalues: OptionType = { - label: example.schema, - value: JSON.stringify({ - nodelabels: example.labels, - relationshipTypes: example.relationshipTypes, - }), - }; - accu.push(examplevalues); - return accu; - }, []); - setdefaultExamples(parsedData); - }, []); useEffect(() => { if (userCredentials) { if (open && view === 'Dialog') { @@ -265,15 +250,6 @@ export default function EntityExtractionSetting({ ); }; - // Load selectedSchemas from local storage on mount - useEffect(() => { - const storedSchemas = localStorage.getItem('selectedSchemas'); - if (storedSchemas) { - const parsedSchemas = JSON.parse(storedSchemas); - setSelectedSchemas(parsedSchemas.selectedOptions); - } - }, []); - return (
            @@ -290,7 +266,7 @@ export default function EntityExtractionSetting({
            {appLabels.predefinedSchema}
            -
            {appLabels.ownSchema}
            - - } - checked={true} - disabled={true} - aria-label='Selected-postprocessing-jobs' + isChecked={true} + isDisabled={true} + ariaLabel='Selected-postprocessing-jobs' /> ); })} diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/index.tsx index b48b6c6a6..d5ebc04a2 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/index.tsx @@ -32,7 +32,7 @@ export default function PostProcessingCheckList() { .join(' ')} } - checked={ + isChecked={ isCreateCommunities ? isGdsActive && postProcessingTasks.includes(job.title) : postProcessingTasks.includes(job.title) @@ -44,8 +44,8 @@ export default function PostProcessingCheckList() { setPostProcessingTasks((prev) => prev.filter((s) => s !== job.title)); } }} - disabled={isCreateCommunities && !isGdsActive} - aria-label='checkbox-postProcessing' + isDisabled={isCreateCommunities && !isGdsActive} + ariaLabel='checkbox-postProcessing' /> {job.description}
            diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/index.tsx index c7b621748..4226099f9 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/index.tsx @@ -1,6 +1,6 @@ -import { Dialog, Tabs, Box, Typography, Flex, useMediaQuery } from '@neo4j-ndl/react'; +import { Dialog, Tabs, Typography, Flex, useMediaQuery } from '@neo4j-ndl/react'; import graphenhancement from '../../../assets/images/graph-enhancements.svg'; -import { useEffect, useState } from 'react'; +import { useState } from 'react'; import DeletePopUpForOrphanNodes from './DeleteTabForOrphanNodes'; import deleteOrphanAPI from '../../../services/DeleteOrphanNodes'; import { UserCredentials } from '../../../types'; @@ -11,15 +11,7 @@ import DeduplicationTab from './Deduplication'; import { tokens } from '@neo4j-ndl/base'; import PostProcessingCheckList from './PostProcessingCheckList'; -export default function GraphEnhancementDialog({ - open, - onClose, - closeSettingModal, -}: { - open: boolean; - onClose: () => void; - closeSettingModal: () => void; -}) { +export default function GraphEnhancementDialog({ open, onClose }: { open: boolean; onClose: () => void }) { const { breakpoints } = tokens; const [orphanDeleteAPIloading, setorphanDeleteAPIloading] = useState(false); const { setShowTextFromSchemaDialog } = useFileContext(); @@ -36,9 +28,6 @@ export default function GraphEnhancementDialog({ console.log(error); } }; - useEffect(() => { - closeSettingModal(); - }, []); const [activeTab, setactiveTab] = useState(0); return ( @@ -47,14 +36,14 @@ export default function GraphEnhancementDialog({ id: 'graph-enhancement-popup', className: 'n-p-token-4 n-rounded-lg', }} - open={open} + isOpen={open} size='unset' - disableCloseButton={false} + hasDisabledCloseButton={false} onClose={onClose} > - - +
            +
            - +
            Graph Enhancements {isTablet @@ -76,23 +65,43 @@ export default function GraphEnhancementDialog({ - + Entity Extraction Settings - + Disconnected Nodes - + De-Duplication Of Nodes - + Post Processing Jobs - - - +
            +
            +
            diff --git a/frontend/src/components/Popups/LargeFilePopUp/ConfirmationDialog.tsx b/frontend/src/components/Popups/LargeFilePopUp/ConfirmationDialog.tsx index 08991c44b..c0159be65 100644 --- a/frontend/src/components/Popups/LargeFilePopUp/ConfirmationDialog.tsx +++ b/frontend/src/components/Popups/LargeFilePopUp/ConfirmationDialog.tsx @@ -70,12 +70,14 @@ function ConfirmationDialog({ return ( { setChecked([]); onClose(); }} + htmlAttributes={{ + 'aria-labelledby': 'form-dialog-title', + }} > {largeFiles.length === 0 && loading ? ( diff --git a/frontend/src/components/Popups/LargeFilePopUp/LargeFilesAlert.tsx b/frontend/src/components/Popups/LargeFilePopUp/LargeFilesAlert.tsx index cc684156b..b8dfa0251 100644 --- a/frontend/src/components/Popups/LargeFilePopUp/LargeFilesAlert.tsx +++ b/frontend/src/components/Popups/LargeFilePopUp/LargeFilesAlert.tsx @@ -1,4 +1,4 @@ -import { Box, Checkbox, Flex, Typography } from '@neo4j-ndl/react'; +import { Checkbox, Flex, Typography } from '@neo4j-ndl/react'; import { DocumentTextIconOutline } from '@neo4j-ndl/react/icons'; import { LargefilesProps } from '../../../types'; import { List, ListItem, ListItemAvatar, ListItemButton, ListItemIcon, ListItemText } from '@mui/material'; @@ -30,16 +30,16 @@ const LargeFilesAlert: FC = ({ largeFiles, handleToggle, checke [colorMode] ); return ( - - +
            +
            alert icon - +
            Large Document Notice - + One or more of your selected documents are large and may take extra time to process. Please review the estimated times below @@ -51,7 +51,7 @@ const LargeFilesAlert: FC = ({ largeFiles, handleToggle, checke { if (e.target.checked) { handleToggle(true, f.id); @@ -59,8 +59,8 @@ const LargeFilesAlert: FC = ({ largeFiles, handleToggle, checke handleToggle(false, f.id); } }} - checked={checked.indexOf(f.id) !== -1} - tabIndex={-1} + isChecked={checked.indexOf(f.id) !== -1} + htmlAttributes={{ tabIndex: -1 }} /> @@ -96,9 +96,9 @@ const LargeFilesAlert: FC = ({ largeFiles, handleToggle, checke ); })} - - - +
            +
            +
            ); }; export default LargeFilesAlert; diff --git a/frontend/src/components/Popups/RetryConfirmation/Index.tsx b/frontend/src/components/Popups/RetryConfirmation/Index.tsx index 6ebb02e33..5112ca688 100644 --- a/frontend/src/components/Popups/RetryConfirmation/Index.tsx +++ b/frontend/src/components/Popups/RetryConfirmation/Index.tsx @@ -27,11 +27,11 @@ function RetryConfirmationDialog({ const file = filesData.find((c) => c.id === fileId); const RetryOptionsForFile = file?.status != 'Completed' ? RETRY_OPIONS : RETRY_OPIONS.slice(0, 2); return ( - + Reprocess Options {alertStatus.showAlert && ( - + {alertStatus.alertMessage} )} @@ -47,17 +47,19 @@ function RetryConfirmationDialog({ }); }); }} - name='retryoptions' - checked={o === file?.retryOption && file?.retryOptionStatus} + htmlAttributes={{ + name: 'retryoptions', + onKeyDown: (e) => { + if (e.code === 'Enter' && file?.retryOption.length) { + retryHandler(file?.name as string, file?.retryOption as string); + } + }, + }} + isChecked={o === file?.retryOption && file?.retryOptionStatus} label={o .split('_') .map((s) => capitalize(s)) .join(' ')} - onKeyDown={(e) => { - if (e.code === 'Enter' && file?.retryOption.length) { - retryHandler(file?.name as string, file?.retryOption as string); - } - }} /> ); })} diff --git a/frontend/src/components/Popups/Settings/SchemaFromText.tsx b/frontend/src/components/Popups/Settings/SchemaFromText.tsx index 1b9136198..f59ec86bf 100644 --- a/frontend/src/components/Popups/Settings/SchemaFromText.tsx +++ b/frontend/src/components/Popups/Settings/SchemaFromText.tsx @@ -1,4 +1,4 @@ -import { Checkbox, Dialog, Textarea } from '@neo4j-ndl/react'; +import { Checkbox, Dialog, TextArea } from '@neo4j-ndl/react'; import { useCallback, useState } from 'react'; import { getNodeLabelsAndRelTypesFromText } from '../../../services/SchemaFromTextAPI'; import { useCredentials } from '../../../context/UserCredentials'; @@ -7,15 +7,7 @@ import { buttonCaptions } from '../../../utils/Constants'; import ButtonWithToolTip from '../../UI/ButtonWithToolTip'; import { showNormalToast, showSuccessToast } from '../../../utils/toasts'; -const SchemaFromTextDialog = ({ - open, - onClose, - openSettingsDialog, -}: { - open: boolean; - onClose: () => void; - openSettingsDialog: () => void; -}) => { +const SchemaFromTextDialog = ({ open, onClose }: { open: boolean; onClose: () => void }) => { const [userText, setUserText] = useState(''); const [loading, setloading] = useState(false); const { setSelectedNodes, setSelectedRels } = useFileContext(); @@ -84,7 +76,6 @@ const SchemaFromTextDialog = ({ onClose(); setUserText(''); setIsSchema(false); - openSettingsDialog(); } catch (error) { setloading(false); console.log(error); @@ -94,26 +85,30 @@ const SchemaFromTextDialog = ({ return ( { setloading(false); setIsSchema(false); setUserText(''); onClose(); }} + htmlAttributes={{ + 'aria-labelledby': 'form-dialog-title', + }} > - Entity Graph Extraction Settings + Entity Graph Extraction Settings - + )); const isMultiModes = useMemo( () => activeChatmodes != null && Object.keys(activeChatmodes).length > 1, @@ -320,7 +318,7 @@ const ChatInfoModal: React.FC = ({ [activeChatmodes] ); return ( -
            +
            = ({ - + {!supportedLLmsForRagas.includes(metricmodel) && ( = ({ about 20 seconds . You'll see detailed scores shortly. -
            - { - setExpandedId(e); - }} - > - - Determines How accurately the answer reflects the provided information. - - - Determines How well the answer addresses the user's question. - - {(isAdditionalMetricsWithSingleMode || isAdditionalMetricsEnabled) && ( - <> - - Determines How much the generated answer matches the reference answer, word-for-word - - - Determines How well the generated answer understands the meaning of the reference answer. - - - Determines Measures the recall of entities present in both reference and retrieved contexts - relative to the reference. - - - )} - -
            {showMultiModeMetrics && isMultiModes && ( ; - closeHandler?: () => void; + closeHandler?: ( + event: Event | undefined, + closeReason: { + type: 'backdropClick' | 'itemClick' | 'escapeKeyDown'; + id?: string; + } + ) => void; open: boolean; isRoot: boolean; }) { diff --git a/frontend/src/components/ChatBot/ChunkInfo.tsx b/frontend/src/components/ChatBot/ChunkInfo.tsx index 0ebf4dc59..2db5a2cbd 100644 --- a/frontend/src/components/ChatBot/ChunkInfo.tsx +++ b/frontend/src/components/ChatBot/ChunkInfo.tsx @@ -268,4 +268,4 @@ const ChunkInfo: FC = ({ loading, chunks, mode }) => { ); }; -export default ChunkInfo; \ No newline at end of file +export default ChunkInfo; diff --git a/frontend/src/components/ChatBot/CommunitiesInfo.tsx b/frontend/src/components/ChatBot/CommunitiesInfo.tsx index f052c7a2f..30d533193 100644 --- a/frontend/src/components/ChatBot/CommunitiesInfo.tsx +++ b/frontend/src/components/ChatBot/CommunitiesInfo.tsx @@ -76,4 +76,4 @@ const CommunitiesInfo: FC = ({ loading, communities, mode }) = ); }; -export default CommunitiesInfo; \ No newline at end of file +export default CommunitiesInfo; diff --git a/frontend/src/components/ChatBot/EntitiesInfo.tsx b/frontend/src/components/ChatBot/EntitiesInfo.tsx index 7a5a0510a..0a90862a4 100644 --- a/frontend/src/components/ChatBot/EntitiesInfo.tsx +++ b/frontend/src/components/ChatBot/EntitiesInfo.tsx @@ -148,4 +148,4 @@ const EntitiesInfo: FC = ({ loading, mode, graphonly_entities, in ); }; -export default EntitiesInfo; \ No newline at end of file +export default EntitiesInfo; diff --git a/frontend/src/components/ChatBot/ExpandedChatButtonContainer.tsx b/frontend/src/components/ChatBot/ExpandedChatButtonContainer.tsx index ae3a7818f..934e4c624 100644 --- a/frontend/src/components/ChatBot/ExpandedChatButtonContainer.tsx +++ b/frontend/src/components/ChatBot/ExpandedChatButtonContainer.tsx @@ -13,7 +13,11 @@ const ExpandedChatButtonContainer: React.FC = ({ closeChatBot, delete return (
            setshowChatModeOption(false)} + closeHandler={(_, reason) => { + if (reason.type === 'backdropClick') { + setshowChatModeOption(false); + } + }} open={showChatModeOption} menuAnchor={chatAnchor} isRoot={false} diff --git a/frontend/src/components/ChatBot/MetricsCheckbox.tsx b/frontend/src/components/ChatBot/MetricsCheckbox.tsx index 31c1ab7f5..593468c2b 100644 --- a/frontend/src/components/ChatBot/MetricsCheckbox.tsx +++ b/frontend/src/components/ChatBot/MetricsCheckbox.tsx @@ -9,7 +9,7 @@ function MetricsCheckbox({ }) { return ( diff --git a/frontend/src/components/ChatBot/MetricsTab.tsx b/frontend/src/components/ChatBot/MetricsTab.tsx index 40e0b11fc..33479eb13 100644 --- a/frontend/src/components/ChatBot/MetricsTab.tsx +++ b/frontend/src/components/ChatBot/MetricsTab.tsx @@ -1,4 +1,4 @@ -import { Banner, Box, DataGrid, DataGridComponents, Typography } from '@neo4j-ndl/react'; +import { Banner, Box, DataGrid, DataGridComponents, Flex, IconButton, Popover, Typography } from '@neo4j-ndl/react'; import { memo, useContext, useMemo, useRef } from 'react'; import { useReactTable, @@ -10,6 +10,8 @@ import { } from '@tanstack/react-table'; import { capitalize } from '../../utils/Utils'; import { ThemeWrapperContext } from '../../context/ThemeWrapper'; +import { InformationCircleIconOutline } from '@neo4j-ndl/react/icons'; +import { metricsinfo } from '../../utils/Constants'; function MetricsTab({ metricsLoading, metricDetails, @@ -40,9 +42,21 @@ function MetricsTab({ .join(' ') : capitalize(metric); return ( -
            - {capitilizedMetric} -
            + +
            + {capitilizedMetric} +
            + + + + + + + + {metricsinfo[metric]} + + +
            ); }, header: () => Metric, diff --git a/frontend/src/components/ChatBot/MultiModeMetrics.tsx b/frontend/src/components/ChatBot/MultiModeMetrics.tsx index 6744af10e..0ecae78c3 100644 --- a/frontend/src/components/ChatBot/MultiModeMetrics.tsx +++ b/frontend/src/components/ChatBot/MultiModeMetrics.tsx @@ -4,13 +4,13 @@ import { createColumnHelper, getFilteredRowModel, getPaginationRowModel, - getSortedRowModel, } from '@tanstack/react-table'; import { capitalize } from '../../utils/Utils'; import { useContext, useEffect, useMemo, useRef } from 'react'; -import { Banner, Box, DataGrid, DataGridComponents, Typography } from '@neo4j-ndl/react'; +import { Banner, Box, DataGrid, DataGridComponents, Flex, IconButton, Popover, Typography } from '@neo4j-ndl/react'; import { multimodelmetric } from '../../types'; import { ThemeWrapperContext } from '../../context/ThemeWrapper'; +import { InformationCircleIconOutline } from '@neo4j-ndl/react/icons'; export default function MultiModeMetrics({ data, @@ -52,35 +52,115 @@ export default function MultiModeMetrics({ cell: (info) => { return {info.getValue().toFixed(2)}; }, - header: () => Relevancy, + header: () => ( + + Relevancy + + + + + + + + + Determines How well the answer addresses the user's question. + + + + + ), }), columnHelper.accessor((row) => row.faithfulness as number, { id: 'Score', cell: (info) => { return {info.getValue().toFixed(2)}; }, - header: () => Faithfulness, + header: () => ( + + Faithful + + + + + + + + + Determines How accurately the answer reflects the provided information. + + + + + ), }), columnHelper.accessor((row) => row.context_entity_recall_score as number, { id: 'Recall Score', cell: (info) => { return {info.getValue()?.toFixed(2)}; }, - header: () => Context Score, + header: () => ( + + Context + + + + + + + + + Determines the recall of entities present in both reference and retrieved contexts. + + + + + ), }), columnHelper.accessor((row) => row.semantic_score as number, { id: 'Semantic Score', cell: (info) => { return {info.getValue()?.toFixed(2)}; }, - header: () => Semantic Score, + header: () => ( + + Semantic + + + + + + + + + Determines How well the generated answer understands the meaning of the reference answer. + + + + + ), }), columnHelper.accessor((row) => row.rouge_score as number, { id: 'Rouge Score', cell: (info) => { return {info.getValue()?.toFixed(2)}; }, - header: () => Rouge Score, + header: () => ( + + Rouge + + + + + + + + + Determines How much the generated answer matches the reference answer, word-for-word. + + + + + ), }), ], [] @@ -93,10 +173,10 @@ export default function MultiModeMetrics({ getPaginationRowModel: getPaginationRowModel(), enableGlobalFilter: false, autoResetPageIndex: false, + enableColumnResizing: true, enableRowSelection: true, enableMultiRowSelection: true, - enableSorting: true, - getSortedRowModel: getSortedRowModel(), + enableSorting: false, }); useEffect(() => { if (isWithAdditionalMetrics === false) { diff --git a/frontend/src/components/ChatBot/chatInfo.ts b/frontend/src/components/ChatBot/chatInfo.ts index 1a229dc70..c7e990ae7 100644 --- a/frontend/src/components/ChatBot/chatInfo.ts +++ b/frontend/src/components/ChatBot/chatInfo.ts @@ -37,4 +37,4 @@ export const handleGraphNodeClick = async ( setLoadingGraphView(false); } } -}; \ No newline at end of file +}; diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 9996ed0a2..98d55b40e 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -116,12 +116,13 @@ const Content: React.FC = ({ setchatModes, } = useFileContext(); - const [viewPoint, setViewPoint] = useState<'tableView' | 'showGraphView' | 'chatInfoView'|'neighborView'>('tableView'); + const [viewPoint, setViewPoint] = useState<'tableView' | 'showGraphView' | 'chatInfoView' | 'neighborView'>( + 'tableView' + ); const [showDeletePopUp, setshowDeletePopUp] = useState(false); const [deleteLoading, setdeleteLoading] = useState(false); const [searchParams] = useSearchParams(); - const { updateStatusForLargeFiles } = useServerSideEvent( (inMinutes, time, fileName) => { showNormalToast(`${fileName} will take approx ${time} ${inMinutes ? 'Min' : 'Sec'}`); @@ -992,4 +993,4 @@ const Content: React.FC = ({ ); }; -export default Content; \ No newline at end of file +export default Content; diff --git a/frontend/src/components/DataSources/AWS/S3Modal.tsx b/frontend/src/components/DataSources/AWS/S3Modal.tsx index 51144c930..0e9b2f49f 100644 --- a/frontend/src/components/DataSources/AWS/S3Modal.tsx +++ b/frontend/src/components/DataSources/AWS/S3Modal.tsx @@ -40,6 +40,12 @@ const S3Modal: React.FC = ({ hideModal, open }) => { processingProgress: undefined, retryOption: '', retryOptionStatus: false, + chunkNodeCount: 0, + chunkRelCount: 0, + entityNodeCount: 0, + entityEntityRelCount: 0, + communityNodeCount: 0, + communityRelCount: 0, }; if (url) { setValid(validation(bucketUrl) && isFocused); diff --git a/frontend/src/components/DataSources/GCS/GCSModal.tsx b/frontend/src/components/DataSources/GCS/GCSModal.tsx index 8893c4f70..288bff00a 100644 --- a/frontend/src/components/DataSources/GCS/GCSModal.tsx +++ b/frontend/src/components/DataSources/GCS/GCSModal.tsx @@ -33,6 +33,12 @@ const GCSModal: React.FC = ({ hideModal, open, openGCSModal }) => processingProgress: undefined, retryOption: '', retryOptionStatus: false, + chunkNodeCount: 0, + chunkRelCount: 0, + entityNodeCount: 0, + entityEntityRelCount: 0, + communityNodeCount: 0, + communityRelCount: 0, }; const reset = () => { diff --git a/frontend/src/components/DataSources/Local/DropZone.tsx b/frontend/src/components/DataSources/Local/DropZone.tsx index 38a6dd1d9..209573eaf 100644 --- a/frontend/src/components/DataSources/Local/DropZone.tsx +++ b/frontend/src/components/DataSources/Local/DropZone.tsx @@ -34,6 +34,12 @@ const DropZone: FunctionComponent = () => { processingProgress: undefined, retryOptionStatus: false, retryOption: '', + chunkNodeCount: 0, + chunkRelCount: 0, + entityNodeCount: 0, + entityEntityRelCount: 0, + communityNodeCount: 0, + communityRelCount: 0, }; const copiedFilesData: CustomFile[] = [...filesData]; diff --git a/frontend/src/components/DataSources/Local/DropZoneForSmallLayouts.tsx b/frontend/src/components/DataSources/Local/DropZoneForSmallLayouts.tsx index 1b27f4eb7..0e78b4704 100644 --- a/frontend/src/components/DataSources/Local/DropZoneForSmallLayouts.tsx +++ b/frontend/src/components/DataSources/Local/DropZoneForSmallLayouts.tsx @@ -169,6 +169,12 @@ export default function DropZoneForSmallLayouts() { processingProgress: undefined, retryOption: '', retryOptionStatus: false, + chunkNodeCount: 0, + chunkRelCount: 0, + entityNodeCount: 0, + entityEntityRelCount: 0, + communityNodeCount: 0, + communityRelCount: 0, }; const copiedFilesData: CustomFile[] = [...filesData]; diff --git a/frontend/src/components/FileTable.tsx b/frontend/src/components/FileTable.tsx index ad06a28c3..22f48c119 100644 --- a/frontend/src/components/FileTable.tsx +++ b/frontend/src/components/FileTable.tsx @@ -3,6 +3,7 @@ import { DataGridComponents, Flex, IconButton, + Popover, ProgressBar, StatusIndicator, TextLink, @@ -41,6 +42,7 @@ import { ClipboardDocumentIconSolid, MagnifyingGlassCircleIconSolid, DocumentTextIconSolid, + InformationCircleIconOutline, } from '@neo4j-ndl/react/icons'; import CustomProgressBar from './UI/CustomProgressBar'; import subscribe from '../services/PollingAPI'; @@ -53,6 +55,7 @@ import { IconButtonWithToolTip } from './UI/IconButtonToolTip'; import { batchSize, largeFileSize, llms } from '../utils/Constants'; import { showErrorToast, showNormalToast } from '../utils/toasts'; import { ThemeWrapperContext } from '../context/ThemeWrapper'; + let onlyfortheFirstRender = true; const FileTable = forwardRef((props, ref) => { @@ -505,13 +508,67 @@ const FileTable = forwardRef((props, ref) => { }), columnHelper.accessor((row) => row.nodesCount, { id: 'NodesCount', - cell: (info) => {info.getValue()}, + cell: (info) => { + const hasNodeBreakDownValues = + info.row.original.chunkNodeCount > 0 || + info.row.original.communityNodeCount > 0 || + info.row.original.entityNodeCount > 0; + return ( + + {info.getValue()} + {hasNodeBreakDownValues && + (info.row.original.status === 'Completed' || info.row.original.status === 'Failed') && ( + + + + + + + +
              +
            • Chunk Nodes: {info.row.original.chunkNodeCount}
            • +
            • Entity Nodes: {info.row.original.entityNodeCount}
            • +
            • Community Nodes: {info.row.original.communityNodeCount}
            • +
            +
            +
            + )} +
            + ); + }, header: () => Nodes, footer: (info) => info.column.id, }), columnHelper.accessor((row) => row.relationshipsCount, { id: 'relationshipCount', - cell: (info) => {info.getValue()}, + cell: (info) => { + const hasRelationsBreakDownValues = + info.row.original.chunkRelCount > 0 || + info.row.original.communityRelCount > 0 || + info.row.original.entityEntityRelCount > 0; + return ( + + {info.getValue()} + {hasRelationsBreakDownValues && + (info.row.original.status === 'Completed' || info.row.original.status === 'Failed') && ( + + + + + + + +
              +
            • Chunk Relations: {info.row.original.chunkRelCount}
            • +
            • Entity Relations: {info.row.original.entityEntityRelCount}
            • +
            • Community Relations: {info.row.original.communityRelCount}
            • +
            +
            +
            + )} +
            + ); + }, header: () => Relations, footer: (info) => info.column.id, }), @@ -719,6 +776,12 @@ const FileTable = forwardRef((props, ref) => { accessToken: item?.accessToken ?? '', retryOption: item.retry_condition ?? '', retryOptionStatus: false, + chunkNodeCount: item.chunkNodeCount ?? 0, + chunkRelCount: item.chunkRelCount ?? 0, + entityNodeCount: item.entityNodeCount ?? 0, + entityEntityRelCount: item.entityEntityRelCount ?? 0, + communityNodeCount: item.communityNodeCount ?? 0, + communityRelCount: item.communityRelCount ?? 0, }); } }); @@ -846,6 +909,12 @@ const FileTable = forwardRef((props, ref) => { status, processed_chunk = 0, total_chunks, + chunkNodeCount, + entityNodeCount, + communityNodeCount, + chunkRelCount, + entityEntityRelCount, + communityRelCount, } = file_name; if (fileName && total_chunks) { setFilesData((prevfiles) => @@ -855,10 +924,16 @@ const FileTable = forwardRef((props, ref) => { ...curfile, status: status, nodesCount: nodeCount, - relationshipCount: relationshipCount, + relationshipsCount: relationshipCount, model: model, processingTotalTime: processingTime?.toFixed(2), processingProgress: Math.floor((processed_chunk / total_chunks) * 100), + chunkNodeCount: chunkNodeCount ?? 0, + entityNodeCount: entityNodeCount ?? 0, + communityNodeCount: communityNodeCount ?? 0, + chunkRelCount: chunkRelCount ?? 0, + entityEntityRelCount: entityEntityRelCount ?? 0, + communityRelCount: communityRelCount ?? 0, }; } return curfile; @@ -876,7 +951,20 @@ const FileTable = forwardRef((props, ref) => { const updateProgress = (i: statusupdate) => { const { file_name } = i; - const { fileName, nodeCount = 0, relationshipCount = 0, status, processed_chunk = 0, total_chunks } = file_name; + const { + fileName, + nodeCount = 0, + relationshipCount = 0, + status, + processed_chunk = 0, + total_chunks, + chunkNodeCount, + entityNodeCount, + communityNodeCount, + chunkRelCount, + entityEntityRelCount, + communityRelCount, + } = file_name; if (fileName && total_chunks) { setFilesData((prevfiles) => prevfiles.map((curfile) => { @@ -885,8 +973,14 @@ const FileTable = forwardRef((props, ref) => { ...curfile, status: status, nodesCount: nodeCount, - relationshipCount: relationshipCount, + relationshipsCount: relationshipCount, processingProgress: Math.floor((processed_chunk / total_chunks) * 100), + chunkNodeCount: chunkNodeCount ?? 0, + entityNodeCount: entityNodeCount ?? 0, + communityNodeCount: communityNodeCount ?? 0, + chunkRelCount: chunkRelCount ?? 0, + entityEntityRelCount: entityEntityRelCount ?? 0, + communityRelCount: communityRelCount ?? 0, }; } return curfile; @@ -984,4 +1078,4 @@ const FileTable = forwardRef((props, ref) => { ); }); -export default FileTable; \ No newline at end of file +export default FileTable; diff --git a/frontend/src/components/Graph/GraphViewModal.tsx b/frontend/src/components/Graph/GraphViewModal.tsx index 7748ebca2..4fe1f52f5 100644 --- a/frontend/src/components/Graph/GraphViewModal.tsx +++ b/frontend/src/components/Graph/GraphViewModal.tsx @@ -447,4 +447,4 @@ const GraphViewModal: React.FunctionComponent = ({ ); }; -export default GraphViewModal; \ No newline at end of file +export default GraphViewModal; diff --git a/frontend/src/components/Layout/Header.tsx b/frontend/src/components/Layout/Header.tsx index 97bcf1902..766758cc5 100644 --- a/frontend/src/components/Layout/Header.tsx +++ b/frontend/src/components/Layout/Header.tsx @@ -198,7 +198,11 @@ const Header: React.FC = ({ chatOnly, deleteOnClick, setOpenConnecti
            setshowChatModeOption(false)} + closeHandler={(_, reason) => { + if (reason.type === 'backdropClick') { + setshowChatModeOption(false); + } + }} open={showChatModeOption} menuAnchor={chatAnchor} isRoot={false} diff --git a/frontend/src/components/Layout/SideNav.tsx b/frontend/src/components/Layout/SideNav.tsx index 3a2e8d6b7..731469e6b 100644 --- a/frontend/src/components/Layout/SideNav.tsx +++ b/frontend/src/components/Layout/SideNav.tsx @@ -224,8 +224,10 @@ const SideNav: React.FC = ({ { - setshowChatMode(false); + closeHandler={(_, reason) => { + if (reason.type === 'backdropClick') { + setshowChatMode(false); + } }} menuAnchor={anchorMenuRef} isRoot={false} diff --git a/frontend/src/components/Popups/ChunkPopUp/index.tsx b/frontend/src/components/Popups/ChunkPopUp/index.tsx index 7aeb5b961..b8020c276 100644 --- a/frontend/src/components/Popups/ChunkPopUp/index.tsx +++ b/frontend/src/components/Popups/ChunkPopUp/index.tsx @@ -1,4 +1,3 @@ - import { Dialog, Typography, Flex, IconButton, useMediaQuery } from '@neo4j-ndl/react'; import { ArrowLeftIconOutline, ArrowRightIconOutline } from '@neo4j-ndl/react/icons'; import { chunkdata } from '../../../types'; @@ -7,7 +6,6 @@ import { useMemo } from 'react'; import chunklogo from '../../../assets/images/chunks.svg'; import { tokens } from '@neo4j-ndl/base'; - const ChunkPopUp = ({ showChunkPopup, chunks, @@ -27,7 +25,6 @@ const ChunkPopUp = ({ currentPage: number | null; totalPageCount: number | null; }) => { - const { breakpoints } = tokens; const isTablet = useMediaQuery(`(min-width:${breakpoints.xs}) and (max-width: ${breakpoints.lg})`); const sortedChunksData = useMemo(() => { diff --git a/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx b/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx index 6096cd06b..934a38f76 100644 --- a/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx +++ b/frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx @@ -474,4 +474,4 @@ export default function ConnectionModal({
            ); -} \ No newline at end of file +} diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx index 321179e9c..97c584b7c 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx @@ -367,4 +367,4 @@ export default function DeduplicationTab() { )} ); -} \ No newline at end of file +} diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx index c0e09ddac..5f0049abd 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx @@ -329,4 +329,4 @@ export default function DeletePopUpForOrphanNodes({ )} ); -} \ No newline at end of file +} diff --git a/frontend/src/components/UI/CustomMenu.tsx b/frontend/src/components/UI/CustomMenu.tsx index e79c1bf00..fa33c368d 100644 --- a/frontend/src/components/UI/CustomMenu.tsx +++ b/frontend/src/components/UI/CustomMenu.tsx @@ -8,7 +8,13 @@ export default function CustomMenu({ isRoot = false, }: { open: boolean; - closeHandler: () => void; + closeHandler: ( + event: Event | undefined, + closeReason: { + type: 'backdropClick' | 'itemClick' | 'escapeKeyDown'; + id?: string; + } + ) => void; items: Menuitems[] | undefined; anchorOrigin: React.RefObject; isRoot?: boolean; diff --git a/frontend/src/hooks/useSourceInput.tsx b/frontend/src/hooks/useSourceInput.tsx index 7965c03b9..20fa0aba0 100644 --- a/frontend/src/hooks/useSourceInput.tsx +++ b/frontend/src/hooks/useSourceInput.tsx @@ -57,6 +57,12 @@ export default function useSourceInput( processingProgress: undefined, retryOption: '', retryOptionStatus: false, + chunkNodeCount: 0, + chunkRelCount: 0, + entityNodeCount: 0, + entityEntityRelCount: 0, + communityNodeCount: 0, + communityRelCount: 0, }; if (url.trim() != '') { setIsValid(validator(url) && isFocused); diff --git a/frontend/src/hooks/useSse.tsx b/frontend/src/hooks/useSse.tsx index 5612dc747..3ab1827f5 100644 --- a/frontend/src/hooks/useSse.tsx +++ b/frontend/src/hooks/useSse.tsx @@ -20,6 +20,12 @@ export default function useServerSideEvent( model, processed_chunk = 0, fileSize, + chunkNodeCount, + entityNodeCount, + communityNodeCount, + chunkRelCount, + entityEntityRelCount, + communityRelCount, } = eventSourceRes; const alertShownStatus = JSON.parse(localStorage.getItem('alertShown') || 'null'); @@ -38,6 +44,12 @@ export default function useServerSideEvent( return { ...curfile, status: total_chunks === processed_chunk ? 'Completed' : status, + chunkNodeCount: chunkNodeCount ?? 0, + entityNodeCount: entityNodeCount ?? 0, + communityNodeCount: communityNodeCount ?? 0, + chunkRelCount: chunkRelCount ?? 0, + entityEntityRelCount: entityEntityRelCount ?? 0, + communityRelCount: communityRelCount ?? 0, nodesCount: nodeCount, relationshipsCount: relationshipCount, model: model, @@ -61,6 +73,12 @@ export default function useServerSideEvent( relationshipsCount: relationshipCount, model: model, processingTotalTime: processingTime?.toFixed(2), + chunkNodeCount: chunkNodeCount ?? 0, + entityNodeCount: entityNodeCount ?? 0, + communityNodeCount: communityNodeCount ?? 0, + chunkRelCount: chunkRelCount ?? 0, + entityEntityRelCount: entityEntityRelCount ?? 0, + communityRelCount: communityRelCount ?? 0, }; } return curfile; diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 036449a66..b2fb3e331 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -28,6 +28,12 @@ export interface CustomFileBase extends Partial { isChecked?: boolean; retryOptionStatus: boolean; retryOption: string; + chunkNodeCount: number; + chunkRelCount: number; + entityNodeCount: number; + entityEntityRelCount: number; + communityNodeCount: number; + communityRelCount: number; } export interface CustomFile extends CustomFileBase { id: string; @@ -312,6 +318,12 @@ export interface fileStatus { total_chunks?: number; // total_pages?: number; processed_chunk?: number; + chunkNodeCount: number; + chunkRelCount: number; + entityNodeCount: number; + entityEntityRelCount: number; + communityNodeCount: number; + communityRelCount: number; } export interface PollingAPI_Response extends Partial { data: statusupdate; diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index 642e4b4f0..8e9167cb0 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -13,26 +13,26 @@ export const llms = process.env?.VITE_LLM_MODELS?.trim() != '' ? (process.env.VITE_LLM_MODELS?.split(',') as string[]) : [ - 'diffbot', - 'openai_gpt_3.5', - 'openai_gpt_4o', - 'openai_gpt_4o_mini', - 'gemini_1.5_pro', - 'gemini_1.5_flash', - 'azure_ai_gpt_35', - 'azure_ai_gpt_4o', - 'ollama_llama3', - 'groq_llama3_70b', - 'anthropic_claude_3_5_sonnet', - 'fireworks_llama_v3p2_90b', - 'bedrock_claude_3_5_sonnet', - ]; + 'diffbot', + 'openai_gpt_3.5', + 'openai_gpt_4o', + 'openai_gpt_4o_mini', + 'gemini_1.5_pro', + 'gemini_1.5_flash', + 'azure_ai_gpt_35', + 'azure_ai_gpt_4o', + 'ollama_llama3', + 'groq_llama3_70b', + 'anthropic_claude_3_5_sonnet', + 'fireworks_llama_v3p2_90b', + 'bedrock_claude_3_5_sonnet', + ]; export const defaultLLM = llms?.includes('openai_gpt_4o') ? 'openai_gpt_4o' : llms?.includes('gemini_1.5_pro') - ? 'gemini_1.5_pro' - : 'diffbot'; + ? 'gemini_1.5_pro' + : 'diffbot'; export const supportedLLmsForRagas = [ 'openai_gpt_3.5', 'openai_gpt_4', @@ -77,40 +77,40 @@ export const chatModeReadableLables: Record = { export const chatModes = process.env?.VITE_CHAT_MODES?.trim() != '' ? process.env.VITE_CHAT_MODES?.split(',').map((mode) => ({ - mode: mode.trim(), - description: getDescriptionForChatMode(mode.trim()), - })) + mode: mode.trim(), + description: getDescriptionForChatMode(mode.trim()), + })) : [ - { - mode: chatModeLables.vector, - description: 'Performs semantic similarity search on text chunks using vector indexing.', - }, - { - mode: chatModeLables.graph, - description: 'Translates text to Cypher queries for precise data retrieval from a graph database.', - }, - { - mode: chatModeLables['graph+vector'], - description: 'Combines vector indexing and graph connections for contextually enhanced semantic search.', - }, - { - mode: chatModeLables.fulltext, - description: 'Conducts fast, keyword-based search using full-text indexing on text chunks.', - }, - { - mode: chatModeLables['graph+vector+fulltext'], - description: 'Integrates vector, graph, and full-text indexing for comprehensive search results.', - }, - { - mode: chatModeLables['entity search+vector'], - description: 'Uses vector indexing on entity nodes for highly relevant entity-based search.', - }, - { - mode: chatModeLables['global search+vector+fulltext'], - description: - 'Use vector and full-text indexing on community nodes to provide accurate, context-aware answers globally.', - }, - ]; + { + mode: chatModeLables.vector, + description: 'Performs semantic similarity search on text chunks using vector indexing.', + }, + { + mode: chatModeLables.graph, + description: 'Translates text to Cypher queries for precise data retrieval from a graph database.', + }, + { + mode: chatModeLables['graph+vector'], + description: 'Combines vector indexing and graph connections for contextually enhanced semantic search.', + }, + { + mode: chatModeLables.fulltext, + description: 'Conducts fast, keyword-based search using full-text indexing on text chunks.', + }, + { + mode: chatModeLables['graph+vector+fulltext'], + description: 'Integrates vector, graph, and full-text indexing for comprehensive search results.', + }, + { + mode: chatModeLables['entity search+vector'], + description: 'Uses vector indexing on entity nodes for highly relevant entity-based search.', + }, + { + mode: chatModeLables['global search+vector+fulltext'], + description: + 'Use vector and full-text indexing on community nodes to provide accurate, context-aware answers globally.', + }, + ]; export const chunkSize = process.env.VITE_CHUNK_SIZE ? parseInt(process.env.VITE_CHUNK_SIZE) : 1 * 1024 * 1024; export const timeperpage = process.env.VITE_TIME_PER_PAGE ? parseInt(process.env.VITE_TIME_PER_PAGE) : 50; @@ -352,3 +352,10 @@ export function getStoredSchema() { } return []; } +export const metricsinfo: Record = { + faithfulness: 'Determines How accurately the answer reflects the provided information', + answer_relevancy: "Determines How well the answer addresses the user's question.", + rouge_score: 'Determines How much the generated answer matches the reference answer, word-for-word.', + semantic_score: 'Determines How well the generated answer understands the meaning of the reference answer.', + context_entity_recall_score: 'Determines the recall of entities present in both reference and retrieved contexts', +}; diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 0859c13e9..253a4e287 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -760,15 +760,15 @@ "@types/chroma-js" "2.1.4" chroma-js "2.4.2" -"@neo4j-ndl/base@^3.0.10": - version "3.0.10" - resolved "https://registry.yarnpkg.com/@neo4j-ndl/base/-/base-3.0.10.tgz#909714ecab10bac08e2066841a83babc2931020b" - integrity sha512-ENZebO1o1oq9xTEJEVkKtlrF5QhfxZqM1lmxU6jbrdwa1TA+YeUVnyBBS3HoGcRGMFCJ3ayJQxnpj7J2ZCTSgA== - -"@neo4j-ndl/react@^3.0.17": - version "3.0.17" - resolved "https://registry.yarnpkg.com/@neo4j-ndl/react/-/react-3.0.17.tgz#bf323358fa470ba7f50e334a5381f2006f8ad1ef" - integrity sha512-qj392qAXNWpxjh62m/5EIZBVALaxSsd1ACbVsJaQEWy4QmfUz3KuAs3rsdwSueN2TYbyEy2C0myoLztlU+3D/A== +"@neo4j-ndl/base@^3.0.14": + version "3.0.14" + resolved "https://registry.yarnpkg.com/@neo4j-ndl/base/-/base-3.0.14.tgz#158db809cec3c986cf9170f8967f37cbf5740f61" + integrity sha512-GVRuibSXvhKsJMJH4J7ROQ1yyvNhvyiPBGewFJHR3fspxi/nKV4dh0jCspdSEdrtAhdhI5VGdwQlSDJREjEPzA== + +"@neo4j-ndl/react@^3.0.23": + version "3.0.23" + resolved "https://registry.yarnpkg.com/@neo4j-ndl/react/-/react-3.0.23.tgz#07b1c24f5ca5adee630318b8a0a67419b5736a53" + integrity sha512-/szMXh/2ROpAVrNrNTOP4IK5eMWB5hRNMHXfu7NJOyqYAhWJlMkjZQClGEM7qvBAX6RoV8mmRWafquWMZhdnoA== dependencies: "@dnd-kit/core" "6.1.0" "@dnd-kit/sortable" "8.0.0" From 95eaf19695b1a05b8db663bbdbc6e7cf6ccef9cf Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Wed, 20 Nov 2024 09:24:19 +0000 Subject: [PATCH 242/292] youtube url fix --- frontend/src/components/UI/HoverableLink.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/UI/HoverableLink.tsx b/frontend/src/components/UI/HoverableLink.tsx index a212b0c88..4c320a14a 100644 --- a/frontend/src/components/UI/HoverableLink.tsx +++ b/frontend/src/components/UI/HoverableLink.tsx @@ -28,7 +28,8 @@ const HoverableLink: React.FC = ({ url, children }) => { setHovering(false); }; const isYouTubeURL = (url: string): boolean => { - return url.includes('youtube.com') || url.includes('youtu.be'); + const newurl = new URL(url); + return newurl.host === 'youtube.com' || newurl.host === 'youtu.be'; }; const extractYouTubeVideoId = (url: string): string => { const videoIdRegex = /(?:\/embed\/|\/watch\?v=|\/(?:embed\/|v\/|watch\?.*v=|youtu\.be\/|embed\/|v=))([^&?#]+)/; From 39e2807fbc28706fa7655e64364c09e7d807beda Mon Sep 17 00:00:00 2001 From: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Date: Wed, 20 Nov 2024 12:05:34 +0000 Subject: [PATCH 243/292] Commented CSP middleware and added endpoint backend_connection_configuation --- backend/score.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/backend/score.py b/backend/score.py index 30f634292..666e2d60f 100644 --- a/backend/score.py +++ b/backend/score.py @@ -81,7 +81,7 @@ async def __call__(self, scope: Scope, receive: Receive, send: Send): await gzip_middleware(scope, receive, send) app = FastAPI() # SecWeb(app=app, Option={'referrer': False, 'xframe': False}) -app.add_middleware(ContentSecurityPolicy, Option={'default-src': ["'self'"], 'base-uri': ["'self'"], 'block-all-mixed-content': []}, script_nonce=False, style_nonce=False, report_only=False) +# app.add_middleware(ContentSecurityPolicy, Option={'default-src': ["'self'"], 'base-uri': ["'self'"], 'block-all-mixed-content': []}, script_nonce=False, style_nonce=False, report_only=False) app.add_middleware(XContentTypeOptions) app.add_middleware(XFrame, Option={'X-Frame-Options': 'DENY'}) app.add_middleware(CustomGZipMiddleware, minimum_size=1000, compresslevel=5,paths=["/sources_list","/url/scan","/extract","/chat_bot","/chunk_entities","/get_neighbours","/graph_query","/schema","/populate_graph_schema","/get_unconnected_nodes_list","/get_duplicate_nodes","/fetch_chunktext"]) @@ -918,5 +918,25 @@ async def fetch_chunktext( finally: gc.collect() +@app.post("/backend_connection_configuation") +async def backend_connection_configuation(): + try: + graph = Neo4jGraph() + print(f'login connection status of object: {graph}') + if graph is not None: + graph_connection = True + return create_api_response('Success',message=f"Backend connection successful",data=graph_connection) + else: + graph_connection = False + return create_api_response('Success',message=f"Backend connection is not successful",data=graph_connection) + except Exception as e: + job_status = "Failed" + message="Unable to connect backend DB" + error_message = str(e) + logging.exception(f'{error_message}') + return create_api_response(job_status, message=message, error=error_message) + finally: + gc.collect() + if __name__ == "__main__": uvicorn.run(app) \ No newline at end of file From c7b4dc04c98f29e6cc94b686af1c2bfceab4dce6 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Wed, 20 Nov 2024 12:47:48 +0000 Subject: [PATCH 244/292] added csp header --- frontend/nginx/nginx.conf | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/frontend/nginx/nginx.conf b/frontend/nginx/nginx.conf index bf047145d..3c940690b 100644 --- a/frontend/nginx/nginx.conf +++ b/frontend/nginx/nginx.conf @@ -2,6 +2,14 @@ server { listen 8080; add_header X-Frame-Options "DENY"; add_header X-Content-Type-Options "nosniff"; + set $backendapi "BACKEND_API_URL"; + set $segmentapi "SEGMENT_API_URL"; + set $webhost "*.FRONTEND_HOSTNAME"; + add_header Content-Security-Policy "connect-src 'self' $backendapi $segmentapi; + frame-src 'self' *.youtube.com *.wikipedia.org; + script-src 'self' 'unsafe-inline' https://accounts.google.com/gsi/client; + default-src 'self' $webhost data:; + style-src 'self' *.googleapis.com 'unsafe-inline';" always ; location / { root /usr/share/nginx/html; index index.html index.htm; From f244b9fc42542171c5973647da24e97c9f91d162 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:04:58 +0000 Subject: [PATCH 245/292] removed the useEffect --- frontend/src/components/Content.tsx | 7 ------- 1 file changed, 7 deletions(-) diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 98d55b40e..0d352e159 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -167,13 +167,6 @@ const Content: React.FC = ({ setOpenConnection((prev) => ({ ...prev, openPopUp: true })); } }, []); - useEffect(() => { - if (currentPage >= 1) { - (async () => { - await getChunks(documentName, currentPage); - })(); - } - }, [currentPage, documentName]); useEffect(() => { if (afterFirstRender) { localStorage.setItem('processedCount', JSON.stringify({ db: userCredentials?.uri, count: processedCount })); From 9d17ec13b0f9573d87e9bb1a4761a012879eaf41 Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Thu, 21 Nov 2024 20:43:14 +0530 Subject: [PATCH 246/292] Table issue (#888) * table changes * removed interdeterminant checkbox * removed material ui checkbox * labels changes * node labels * messages fix * aria-label added --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> --- frontend/src/App.css | 2 +- .../components/ChatBot/ChatOnlyComponent.tsx | 100 ++++++++++-------- frontend/src/components/ChatBot/Chatbot.tsx | 4 +- .../Local/DropZoneForSmallLayouts.tsx | 2 +- .../components/Graph/GraphPropertiesPanel.tsx | 71 +++++++------ frontend/src/components/Layout/Header.tsx | 40 +++++-- frontend/src/types.ts | 4 + frontend/src/utils/Constants.ts | 1 + 8 files changed, 140 insertions(+), 84 deletions(-) diff --git a/frontend/src/App.css b/frontend/src/App.css index da6c34af6..70127b6af 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -58,7 +58,7 @@ } .contentWithChatBot { - width: calc(-550px + 100dvw); + width: calc(-528px + 100dvw); height: calc(100dvh - 58px); padding: 3px; display: flex; diff --git a/frontend/src/components/ChatBot/ChatOnlyComponent.tsx b/frontend/src/components/ChatBot/ChatOnlyComponent.tsx index 25e618c16..ebeb3d7d5 100644 --- a/frontend/src/components/ChatBot/ChatOnlyComponent.tsx +++ b/frontend/src/components/ChatBot/ChatOnlyComponent.tsx @@ -1,29 +1,28 @@ +import { useEffect, useState, useCallback, useReducer } from 'react'; +import { useLocation } from 'react-router'; import { MessageContextWrapper, useMessageContext } from '../../context/UserMessages'; import UserCredentialsWrapper, { useCredentials } from '../../context/UserCredentials'; -import Chatbot from './Chatbot'; -import { getIsLoading } from '../../utils/Utils'; import { FileContextProvider } from '../../context/UsersFiles'; -import { useEffect, useState, useCallback } from 'react'; +import Chatbot from './Chatbot'; import ConnectionModal from '../Popups/ConnectionModal/ConnectionModal'; -import { clearChatAPI } from '../../services/QnaAPI'; -import { connectionState, Messages, UserCredentials } from '../../types'; -import { useLocation } from 'react-router'; import Header from '../Layout/Header'; +import { clearChatAPI } from '../../services/QnaAPI'; +import { ChatProps, connectionState, Messages, UserCredentials } from '../../types'; +import { getIsLoading } from '../../utils/Utils'; -interface chatProp { - chatMessages: Messages[]; -} -const ChatContent: React.FC = ({ chatMessages }) => { - const date = new Date(); +const ChatContent: React.FC = ({ chatMessages }) => { const { clearHistoryData, messages, setMessages, setClearHistoryData } = useMessageContext(); const { setUserCredentials, setConnectionStatus, connectionStatus } = useCredentials(); + const [showBackButton, setShowBackButton]= useReducer((state) => !state, false); const [openConnection, setOpenConnection] = useState({ openPopUp: false, chunksExists: false, vectorIndexMisMatch: false, chunksExistsWithDifferentDimension: false, }); - + /** + * Initializes connection settings based on URL parameters. + */ const initialiseConnection = useCallback(() => { const urlParams = new URLSearchParams(window.location.search); const uri = urlParams.get('uri'); @@ -31,22 +30,32 @@ const ChatContent: React.FC = ({ chatMessages }) => { const encodedPassword = urlParams.get('password'); const database = urlParams.get('database'); const port = urlParams.get('port'); - const openModel = urlParams.get('open') === 'true'; - if (openModel || !(uri && user && encodedPassword && database && port)) { + const openModal = urlParams.get('open') === 'true'; + if (openModal || !(uri && user && encodedPassword && database && port)) { setOpenConnection((prev) => ({ ...prev, openPopUp: true })); } else { - const credentialsForAPI = { uri, userName: user, password: atob(atob(encodedPassword)), database, port }; - setUserCredentials({ ...credentialsForAPI }); + const credentialsForAPI: UserCredentials = { + uri, + userName: user, + password: atob(atob(encodedPassword)), + database, + port, + }; + setShowBackButton(); + setUserCredentials(credentialsForAPI); setConnectionStatus(true); setMessages(chatMessages); + // Remove query params from URL window.history.replaceState({}, document.title, window.location.pathname); } - }, [connectionStatus, setUserCredentials]); + }, [chatMessages, setUserCredentials, setConnectionStatus, setMessages]); useEffect(() => { initialiseConnection(); - }, [connectionStatus]); - + }, [initialiseConnection]); + /** + * Handles successful connection establishment. + */ const handleConnectionSuccess = () => { setConnectionStatus(true); setOpenConnection((prev) => ({ ...prev, openPopUp: false })); @@ -54,26 +63,29 @@ const ChatContent: React.FC = ({ chatMessages }) => { urlParams.delete('openModal'); window.history.replaceState({}, document.title, `${window.location.pathname}?${urlParams.toString()}`); }; + /** + * Clears chat history by calling the API. + */ const deleteOnClick = async () => { try { setClearHistoryData(true); - const response = await clearChatAPI( - JSON.parse(localStorage.getItem('neo4j.connection') || '{}') as UserCredentials, - sessionStorage.getItem('session_id') ?? '' - ); + const credentials = JSON.parse(localStorage.getItem('neo4j.connection') || '{}') as UserCredentials; + const sessionId = sessionStorage.getItem('session_id') || ''; + const response = await clearChatAPI(credentials, sessionId); if (response.data.status !== 'Success') { setClearHistoryData(false); } } catch (error) { - console.log(error); + console.error('Error clearing chat history:', error); setClearHistoryData(false); } }; useEffect(() => { if (clearHistoryData) { + const currentDateTime = new Date(); setMessages([ { - datetime: `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`, + datetime: `${currentDateTime.toLocaleDateString()} ${currentDateTime.toLocaleTimeString()}`, id: 2, modes: { 'graph+vector+fulltext': { @@ -87,7 +99,7 @@ const ChatContent: React.FC = ({ chatMessages }) => { ]); setClearHistoryData(false); } - }, [clearHistoryData]); + }, [clearHistoryData, setMessages]); return ( <> = ({ chatMessages }) => { onSuccess={handleConnectionSuccess} isChatOnly={true} /> - { +
            +
            -
            -
            - -
            +
            - } +
            ); }; +/** +* ChatOnlyComponent +* Wrapper component to provide necessary context and initialize chat functionality. +*/ const ChatOnlyComponent: React.FC = () => { const location = useLocation(); + const chatMessages = location.state?.messages as Messages[] || []; return ( - + ); }; - -export default ChatOnlyComponent; +export default ChatOnlyComponent; \ No newline at end of file diff --git a/frontend/src/components/ChatBot/Chatbot.tsx b/frontend/src/components/ChatBot/Chatbot.tsx index 4d1a1b971..03d027d04 100644 --- a/frontend/src/components/ChatBot/Chatbot.tsx +++ b/frontend/src/components/ChatBot/Chatbot.tsx @@ -410,8 +410,8 @@ const Chatbot: FC = (props) => { return (
            diff --git a/frontend/src/components/DataSources/Local/DropZoneForSmallLayouts.tsx b/frontend/src/components/DataSources/Local/DropZoneForSmallLayouts.tsx index 0e78b4704..f3fbff852 100644 --- a/frontend/src/components/DataSources/Local/DropZoneForSmallLayouts.tsx +++ b/frontend/src/components/DataSources/Local/DropZoneForSmallLayouts.tsx @@ -222,7 +222,7 @@ export default function DropZoneForSmallLayouts() { return ( <>
            - + {isLoading ? : }
            diff --git a/frontend/src/components/Graph/GraphPropertiesPanel.tsx b/frontend/src/components/Graph/GraphPropertiesPanel.tsx index 64332c9ac..006dfc095 100644 --- a/frontend/src/components/Graph/GraphPropertiesPanel.tsx +++ b/frontend/src/components/Graph/GraphPropertiesPanel.tsx @@ -12,41 +12,50 @@ const isNode = (item: BasicNode | BasicRelationship): item is BasicNode => { const GraphPropertiesPanel = ({ inspectedItem, newScheme }: GraphPropertiesPanelProps) => { const inspectedItemType = isNode(inspectedItem) ? 'node' : 'relationship'; + const filteredProperties = + inspectedItemType === 'node' + ? Object.entries((inspectedItem as BasicNode).properties) + .filter(([, value]) => value !== null && value !== undefined && value !== ' ') + .reduce((acc, [key, value]) => { + acc[key] = value; + return acc; + }, {} as Record) + : {}; const properties = inspectedItemType === 'node' ? [ - { - key: '', - value: `${(inspectedItem as BasicNode).id}`, - type: 'String', - }, - ...Object.keys((inspectedItem as BasicNode).properties).map((key) => { - const value = (inspectedItem as BasicNode).properties[key]; - return { key: key, value: value ?? '' }; - }), - ] + { + key: '', + value: `${(inspectedItem as BasicNode).id}`, + type: 'String', + }, + ...Object.keys(filteredProperties).map((key) => { + const value = filteredProperties[key]; + return { key, value }; + }), + ] : [ - { - key: '', - value: `${(inspectedItem as BasicRelationship).id}`, - type: 'String', - }, - { - key: '', - value: `${(inspectedItem as BasicRelationship).from}`, - type: 'String', - }, - { - key: '', - value: `${(inspectedItem as BasicRelationship).to}`, - type: 'String', - }, - { - key: '', - value: `${(inspectedItem as BasicRelationship).caption ?? ''}`, - type: 'String', - }, - ]; + { + key: '', + value: `${(inspectedItem as BasicRelationship).id}`, + type: 'String', + }, + { + key: '', + value: `${(inspectedItem as BasicRelationship).from}`, + type: 'String', + }, + { + key: '', + value: `${(inspectedItem as BasicRelationship).to}`, + type: 'String', + }, + { + key: '', + value: `${(inspectedItem as BasicRelationship).caption ?? ''}`, + type: 'String', + }, + ]; const labelsSorted = useMemo(() => { if (isNode(inspectedItem)) { return [...inspectedItem.labels].sort(sortAlphabetically); diff --git a/frontend/src/components/Layout/Header.tsx b/frontend/src/components/Layout/Header.tsx index 766758cc5..36e4022f3 100644 --- a/frontend/src/components/Layout/Header.tsx +++ b/frontend/src/components/Layout/Header.tsx @@ -8,8 +8,9 @@ import { ArrowTopRightOnSquareIconOutline, TrashIconOutline, ArrowLeftIconOutline, + ArrowDownTrayIconOutline, } from '@neo4j-ndl/react/icons'; -import { Button, Typography } from '@neo4j-ndl/react'; +import { Button, TextLink, Typography } from '@neo4j-ndl/react'; import { Dispatch, memo, SetStateAction, useCallback, useContext, useEffect, useRef, useState } from 'react'; import { IconButtonWithToolTip } from '../UI/IconButtonToolTip'; import { buttonCaptions, tooltips } from '../../utils/Constants'; @@ -21,21 +22,23 @@ import { useMessageContext } from '../../context/UserMessages'; import { RiChatSettingsLine } from 'react-icons/ri'; import ChatModeToggle from '../ChatBot/ChatModeToggle'; import { connectionState } from '../../types'; +import { downloadClickHandler, getIsLoading } from '../../utils/Utils'; interface HeaderProp { chatOnly?: boolean; deleteOnClick?: () => void; setOpenConnection?: Dispatch>; + showBackButton?: boolean; } -const Header: React.FC = ({ chatOnly, deleteOnClick, setOpenConnection }) => { +const Header: React.FC = ({ chatOnly, deleteOnClick, setOpenConnection, showBackButton }) => { const { colorMode, toggleColorMode } = useContext(ThemeWrapperContext); const navigate = useNavigate(); const { messages } = useMessageContext(); const handleURLClick = useCallback((url: string) => { window.open(url, '_blank'); }, []); - + const downloadLinkRef = useRef(null); const { isSchema, setIsSchema } = useFileContext(); const { connectionStatus } = useCredentials(); const chatAnchor = useRef(null); @@ -46,6 +49,7 @@ const Header: React.FC = ({ chatOnly, deleteOnClick, setOpenConnecti const openChatPopout = useCallback(() => { let session = localStorage.getItem('neo4j.connection'); + const isLoading = getIsLoading(messages); if (session) { const neo4jConnection = JSON.parse(session); const { uri } = neo4jConnection; @@ -57,7 +61,7 @@ const Header: React.FC = ({ chatOnly, deleteOnClick, setOpenConnecti const chatUrl = `/chat-only?uri=${encodeURIComponent( uri )}&user=${userName}&password=${encodedPassword}&database=${database}&port=${port}&connectionStatus=${connectionStatus}`; - navigate(chatUrl, { state: messages }); + navigate(chatUrl, { state: { messages, isLoading } });; } else { const chatUrl = `/chat-only?openModal=true`; window.open(chatUrl, '_blank'); @@ -140,6 +144,7 @@ const Header: React.FC = ({ chatOnly, deleteOnClick, setOpenConnecti text={tooltips.openChatPopout} size='large' clean + disabled={getIsLoading(messages)} > @@ -165,9 +170,10 @@ const Header: React.FC = ({ chatOnly, deleteOnClick, setOpenConnecti {buttonCaptions.connectToNeo4j} )} - + {showBackButton && ( + )}
            { @@ -181,12 +187,34 @@ const Header: React.FC = ({ chatOnly, deleteOnClick, setOpenConnecti
            + <> + downloadClickHandler( + { conversation: messages }, + downloadLinkRef, + 'graph-builder-conversation.json' + )} + disabled={messages.length === 1 || getIsLoading(messages)} + placement={chatOnly ? 'left' : 'bottom'} + label={tooltips.downloadChat} + > + + + + <> + + "" + + diff --git a/frontend/src/types.ts b/frontend/src/types.ts index b2fb3e331..fcb170604 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -902,3 +902,7 @@ export interface GraphViewHandlerProps { entityInfo?: Entity[]; mode?: string; } + +export interface ChatProps { + chatMessages: Messages[]; +} diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index 8e9167cb0..ac8c1a502 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -144,6 +144,7 @@ export const tooltips = { clearGraphSettings: 'Clear configured Graph Schema', applySettings: 'Apply Graph Schema', openChatPopout: 'Chat', + downloadChat:'Download Conversation' }; export const buttonCaptions = { From 86c33ba864e3a0f3513105a8aaf77d450face438 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:20:22 +0000 Subject: [PATCH 247/292] key fix --- frontend/src/components/Content.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 0d352e159..97e2dcde6 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -596,7 +596,7 @@ const Content: React.FC = ({ status: 'Reprocess', processingProgress: isStartFromBegining ? 0 : f.processingProgress, nodesCount: isStartFromBegining ? 0 : f.nodesCount, - relationshipCount: isStartFromBegining ? 0 : f.relationshipsCount, + relationshipsCount: isStartFromBegining ? 0 : f.relationshipsCount, } : f; }); From 09df9e67229dc59961562a0ed4f9f537ba1a69f6 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Fri, 22 Nov 2024 11:28:59 +0530 Subject: [PATCH 248/292] Update README.md --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index fcc3026cc..5d8e90e2f 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,21 @@ If you are using Neo4j Desktop, you will not be able to use the docker-compose b #### Running through docker-compose By default only OpenAI and Diffbot are enabled since Gemini requires extra GCP configurations. +Set the values for nginx configuration in frontend/nginx/nginx.conf + +``` +set $backendapi "BACKEND_API_URL"; +set $segmentapi "SEGMENT_API_URL"; +set $webhost "*.FRONTEND_HOSTNAME"; +``` +Here the SEGMENT_API_URL is optional it will not impact the application it is used for analytics purpose. +Both BACKEND_API_URL and FRONTEND_HOSTNAME is compulsory to run the application. +BACKEND_API_URL is the url where backend server is up and running. +FRONTEND_HOSTNAME is the hostname of the frontend application url. +#example: +if the frontend application is running on http://localhost:8080 +the host name will be localhost:8080 + According to the environment, we are configuring the models which indicated by VITE_LLM_MODELS_PROD variable we can configure models based on our needs. EX: ```env From 56102474e33178628b8cea5c90153b15ba590028 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Fri, 22 Nov 2024 11:30:26 +0530 Subject: [PATCH 249/292] Update README.md --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5d8e90e2f..b745e0c51 100644 --- a/README.md +++ b/README.md @@ -32,16 +32,17 @@ If you are using Neo4j Desktop, you will not be able to use the docker-compose b #### Running through docker-compose By default only OpenAI and Diffbot are enabled since Gemini requires extra GCP configurations. -Set the values for nginx configuration in frontend/nginx/nginx.conf +Set the values for nginx configuration in frontend/nginx/nginx.conf. ``` set $backendapi "BACKEND_API_URL"; set $segmentapi "SEGMENT_API_URL"; set $webhost "*.FRONTEND_HOSTNAME"; ``` -Here the SEGMENT_API_URL is optional it will not impact the application it is used for analytics purpose. -Both BACKEND_API_URL and FRONTEND_HOSTNAME is compulsory to run the application. +Here the SEGMENT_API_URL is optional it will not impact the application it is used for analytics purpose.Both BACKEND_API_URL and FRONTEND_HOSTNAME is compulsory to run the application. + BACKEND_API_URL is the url where backend server is up and running. + FRONTEND_HOSTNAME is the hostname of the frontend application url. #example: if the frontend application is running on http://localhost:8080 From a247d759cc57a194a68b716e322b73f08851973f Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Fri, 22 Nov 2024 11:31:30 +0530 Subject: [PATCH 250/292] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index b745e0c51..7ad06358d 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,9 @@ Here the SEGMENT_API_URL is optional it will not impact the application it is us BACKEND_API_URL is the url where backend server is up and running. FRONTEND_HOSTNAME is the hostname of the frontend application url. + #example: + if the frontend application is running on http://localhost:8080 the host name will be localhost:8080 From 69d46ab38674fb521924748190582f958fcdf00f Mon Sep 17 00:00:00 2001 From: aashipandya <156318202+aashipandya@users.noreply.github.com> Date: Fri, 22 Nov 2024 12:26:27 +0530 Subject: [PATCH 251/292] removed extra document nodes and combine chunk logic (#894) --- backend/src/llm.py | 13 ++++++++++++- backend/src/shared/common_fn.py | 4 ++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/backend/src/llm.py b/backend/src/llm.py index 93ee0f08f..bfb2a7abc 100644 --- a/backend/src/llm.py +++ b/backend/src/llm.py @@ -144,6 +144,16 @@ def get_combined_chunks(chunkId_chunkDoc_list): ) return combined_chunk_document_list +def get_chunk_id_as_doc_metadata(chunkId_chunkDoc_list): + combined_chunk_document_list = [ + Document( + page_content=document["chunk_doc"].page_content, + metadata={"chunk_id": [document["chunk_id"]]}, + ) + for document in chunkId_chunkDoc_list + ] + return combined_chunk_document_list + async def get_graph_document_list( llm, combined_chunk_document_list, allowedNodes, allowedRelationship @@ -191,7 +201,8 @@ async def get_graph_document_list( async def get_graph_from_llm(model, chunkId_chunkDoc_list, allowedNodes, allowedRelationship): llm, model_name = get_llm(model) - combined_chunk_document_list = get_combined_chunks(chunkId_chunkDoc_list) + #combined_chunk_document_list = get_combined_chunks(chunkId_chunkDoc_list) + combined_chunk_document_list = get_chunk_id_as_doc_metadata(chunkId_chunkDoc_list) if allowedNodes is None or allowedNodes=="": allowedNodes =[] diff --git a/backend/src/shared/common_fn.py b/backend/src/shared/common_fn.py index 6d24912c7..e6de7a583 100644 --- a/backend/src/shared/common_fn.py +++ b/backend/src/shared/common_fn.py @@ -60,7 +60,7 @@ def get_chunk_and_graphDocument(graph_document_list, chunkId_chunkDoc_list): logging.info("creating list of chunks and graph documents in get_chunk_and_graphDocument func") lst_chunk_chunkId_document=[] for graph_document in graph_document_list: - for chunk_id in graph_document.source.metadata['combined_chunk_ids'] : + for chunk_id in graph_document.source.metadata['chunk_id'] : lst_chunk_chunkId_document.append({'graph_doc':graph_document,'chunk_id':chunk_id}) return lst_chunk_chunkId_document @@ -94,7 +94,7 @@ def load_embedding_model(embedding_model_name: str): return embeddings, dimension def save_graphDocuments_in_neo4j(graph:Neo4jGraph, graph_document_list:List[GraphDocument]): - graph.add_graph_documents(graph_document_list, baseEntityLabel=True,include_source=True) + graph.add_graph_documents(graph_document_list, baseEntityLabel=True) # graph.add_graph_documents(graph_document_list) def handle_backticks_nodes_relationship_id_type(graph_document_list:List[GraphDocument]): From 4721318f2c1856b76b21312aa335d5c03b75d53e Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Fri, 22 Nov 2024 13:34:29 +0530 Subject: [PATCH 252/292] Update README.md --- README.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 7ad06358d..557eed6dd 100644 --- a/README.md +++ b/README.md @@ -210,13 +210,14 @@ VITE_BACKEND_API_URL=${VITE_BACKEND_API_URL-backendurl} ## Usage -1. Connect to Neo4j Aura Instance by passing URI and password or using Neo4j credentials file. -2. Choose your source from a list of Unstructured sources to create graph. -3. Change the LLM (if required) from drop down, which will be used to generate graph. -4. Optionally, define schema(nodes and relationship labels) in entity graph extraction settings. -5. Either select multiple files to 'Generate Graph' or all the files in 'New' status will be processed for graph creation. -6. Have a look at the graph for individual files using 'View' in grid or select one or more files and 'Preview Graph' -7. Ask questions related to the processed/completed sources to chat-bot, Also get detailed information about your answers generated by LLM. +1. Connect to Neo4j Aura Instance which can be both AURA DS or AURA DB by passing URI and password or using Neo4j credentials file. +2. To differntiate we have added different icons. For AURA DB we have a database icon and for AURA DS we have scientific molecule icon right under Neo4j Connection details label. +3. Choose your source from a list of Unstructured sources to create graph. +4. Change the LLM (if required) from drop down, which will be used to generate graph. +5. Optionally, define schema(nodes and relationship labels) in entity graph extraction settings. +6. Either select multiple files to 'Generate Graph' or all the files in 'New' status will be processed for graph creation. +7. Have a look at the graph for individual files using 'View' in grid or select one or more files and 'Preview Graph' +8. Ask questions related to the processed/completed sources to chat-bot, Also get detailed information about your answers generated by LLM. ## Links From ab0405fc00b443510164d6e888af98083b6ba2a5 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Fri, 22 Nov 2024 13:36:25 +0530 Subject: [PATCH 253/292] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 557eed6dd..498190c5d 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ BACKEND_API_URL is the url where backend server is up and running. FRONTEND_HOSTNAME is the hostname of the frontend application url. -#example: +EX: if the frontend application is running on http://localhost:8080 the host name will be localhost:8080 From 9628b6d8501f9f03fa2a987f2481baa8d5677947 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Fri, 22 Nov 2024 10:00:39 +0000 Subject: [PATCH 254/292] conditional deployment based on the enviornment --- docker-compose.yml | 5 +++-- frontend/Dockerfile | 4 +++- frontend/example.env | 2 ++ frontend/nginx/nginx.local.conf | 16 ++++++++++++++++ frontend/nginx/{nginx.conf => nginx.prod.conf} | 7 ++----- 5 files changed, 26 insertions(+), 8 deletions(-) create mode 100644 frontend/nginx/nginx.local.conf rename frontend/nginx/{nginx.conf => nginx.prod.conf} (68%) diff --git a/docker-compose.yml b/docker-compose.yml index 8a0fdc4b2..ea074f50b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -63,11 +63,12 @@ services: - VITE_BATCH_SIZE=${VITE_BATCH_SIZE-2} - VITE_LLM_MODELS=${VITE_LLM_MODELS-} - VITE_LLM_MODELS_PROD=${VITE_LLM_MODELS_PROD-openai_gpt_4o,openai_gpt_4o_mini,diffbot,gemini_1.5_flash} + - DEPLOYMENT_ENV=local volumes: - ./frontend:/app - /app/node_modules - # env_file: - # - ./frontend/.env + env_file: + - ./frontend/.env container_name: frontend ports: - "8080:8080" diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 311294f4a..d0a258a59 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -33,8 +33,10 @@ RUN VITE_BACKEND_API_URL=$VITE_BACKEND_API_URL \ # Step 2: Serve the application using Nginx FROM nginx:alpine +ARG DEPLOYMENT_ENV="local" +ENV DEPLOYMENT_ENV=$DEPLOYMENT_ENV COPY --from=build /app/dist /usr/share/nginx/html -COPY nginx/nginx.conf /etc/nginx/conf.d/default.conf +COPY /nginx/nginx.${DEPLOYMENT_ENV}.conf /etc/nginx/templates/nginx.conf.template EXPOSE 8080 CMD ["nginx", "-g", "daemon off;"] diff --git a/frontend/example.env b/frontend/example.env index 4063fbc37..901ac6017 100644 --- a/frontend/example.env +++ b/frontend/example.env @@ -10,3 +10,5 @@ VITE_GOOGLE_CLIENT_ID="" VITE_CHAT_MODES="" VITE_BATCH_SIZE=2 VITE_LLM_MODELS_PROD="openai_gpt_4o,openai_gpt_4o_mini,diffbot,gemini_1.5_flash" +VITE_FRONTEND_HOSTNAME="localhost:8080" +VITE_SEGMENT_API_URL="" diff --git a/frontend/nginx/nginx.local.conf b/frontend/nginx/nginx.local.conf new file mode 100644 index 000000000..2bab3515f --- /dev/null +++ b/frontend/nginx/nginx.local.conf @@ -0,0 +1,16 @@ +server { + + listen 8080; + + location / { + root /usr/share/nginx/html; + index index.html index.htm; + try_files $uri $uri/ /index.html; + } + + error_page 401 403 404 index.html; + + location /public { + root /usr/local/var/www; + } +} \ No newline at end of file diff --git a/frontend/nginx/nginx.conf b/frontend/nginx/nginx.prod.conf similarity index 68% rename from frontend/nginx/nginx.conf rename to frontend/nginx/nginx.prod.conf index 3c940690b..ac6c1db82 100644 --- a/frontend/nginx/nginx.conf +++ b/frontend/nginx/nginx.prod.conf @@ -2,13 +2,10 @@ server { listen 8080; add_header X-Frame-Options "DENY"; add_header X-Content-Type-Options "nosniff"; - set $backendapi "BACKEND_API_URL"; - set $segmentapi "SEGMENT_API_URL"; - set $webhost "*.FRONTEND_HOSTNAME"; - add_header Content-Security-Policy "connect-src 'self' $backendapi $segmentapi; + add_header Content-Security-Policy "connect-src 'self' ${VITE_BACKEND_API_URL} ${VITE_SEGMENT_API_URL}; frame-src 'self' *.youtube.com *.wikipedia.org; script-src 'self' 'unsafe-inline' https://accounts.google.com/gsi/client; - default-src 'self' $webhost data:; + default-src 'self' *.${VITE_FRONTEND_HOSTNAME} data:; style-src 'self' *.googleapis.com 'unsafe-inline';" always ; location / { root /usr/share/nginx/html; From 03526a4f0c376c82836fe7156b619d8f30fdc160 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Fri, 22 Nov 2024 15:48:50 +0530 Subject: [PATCH 255/292] Update README.md --- README.md | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/README.md b/README.md index 498190c5d..cbf625993 100644 --- a/README.md +++ b/README.md @@ -31,25 +31,6 @@ If you are using Neo4j Desktop, you will not be able to use the docker-compose b ### Local deployment #### Running through docker-compose By default only OpenAI and Diffbot are enabled since Gemini requires extra GCP configurations. - -Set the values for nginx configuration in frontend/nginx/nginx.conf. - -``` -set $backendapi "BACKEND_API_URL"; -set $segmentapi "SEGMENT_API_URL"; -set $webhost "*.FRONTEND_HOSTNAME"; -``` -Here the SEGMENT_API_URL is optional it will not impact the application it is used for analytics purpose.Both BACKEND_API_URL and FRONTEND_HOSTNAME is compulsory to run the application. - -BACKEND_API_URL is the url where backend server is up and running. - -FRONTEND_HOSTNAME is the hostname of the frontend application url. - -EX: - -if the frontend application is running on http://localhost:8080 -the host name will be localhost:8080 - According to the environment, we are configuring the models which indicated by VITE_LLM_MODELS_PROD variable we can configure models based on our needs. EX: ```env From 856288053037d331060d38c70e1049dc2269efcb Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Fri, 22 Nov 2024 15:54:29 +0530 Subject: [PATCH 256/292] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index cbf625993..164e51f00 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,7 @@ Allow unauthenticated request : Yes | VITE_CHUNK_SIZE | Optional | 5242880 | Size of each chunk of file for upload | | VITE_GOOGLE_CLIENT_ID | Optional | | Client ID for Google authentication | | VITE_LLM_MODELS_PROD | Optional | openai_gpt_4o,openai_gpt_4o_mini,diffbot,gemini_1.5_flash | To Distinguish models based on the Enviornment PROD or DEV +| VITE_LLM_MODELS | Optional | 'diffbot,openai_gpt_3.5,openai_gpt_4o,openai_gpt_4o_mini,gemini_1.5_pro,gemini_1.5_flash,azure_ai_gpt_35,azure_ai_gpt_4o,ollama_llama3,groq_llama3_70b,anthropic_claude_3_5_sonnet' | Supported Models For the application | GCS_FILE_CACHE | Optional | False | If set to True, will save the files to process into GCS. If set to False, will save the files locally | | ENTITY_EMBEDDING | Optional | False | If set to True, It will add embeddings for each entity in database | | LLM_MODEL_CONFIG_ollama_ | Optional | | Set ollama config as - model_name,model_local_url for local deployments | From c5603e6b7ff8e5a2cb9372e68a40e77f62c91ed7 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Fri, 22 Nov 2024 11:54:54 +0000 Subject: [PATCH 257/292] removed the reference answer checkbox and textarea while additional metrics are loading --- .../src/components/ChatBot/ChatInfoModal.tsx | 10 ++- .../components/ChatBot/ChatOnlyComponent.tsx | 19 +++-- .../components/ChatBot/MultiModeMetrics.tsx | 6 +- .../components/Graph/GraphPropertiesPanel.tsx | 72 +++++++++---------- frontend/src/components/Layout/Header.tsx | 33 ++++++--- frontend/src/utils/Constants.ts | 2 +- 6 files changed, 83 insertions(+), 59 deletions(-) diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index 6a473645b..1609f1eac 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -223,7 +223,9 @@ const ChatInfoModal: React.FC = ({ defaultMode, ]) ); + toggleReferenceVisibility(); } + const metricsResponse = await Promise.allSettled(metricsPromise); const successresponse = []; for (let index = 0; index < metricsResponse.length; index++) { @@ -280,6 +282,7 @@ const ChatInfoModal: React.FC = ({ modesarray ) ); + toggleReferenceVisibility(); } const metricsResponse = await Promise.allSettled(metricsPromise); toggleMetricsLoading(); @@ -425,13 +428,18 @@ const ChatInfoModal: React.FC = ({ toggleReferenceVisibility={toggleReferenceVisibility} isVisible={ isSingleMode && + !metricsLoading && (isAdditionalMetricsWithSingleMode === false || isAdditionalMetricsWithSingleMode === null) } /> = ({ chatMessages }) => { const { clearHistoryData, messages, setMessages, setClearHistoryData } = useMessageContext(); const { setUserCredentials, setConnectionStatus, connectionStatus } = useCredentials(); - const [showBackButton, setShowBackButton]= useReducer((state) => !state, false); + const [showBackButton, setShowBackButton] = useReducer((state) => !state, false); const [openConnection, setOpenConnection] = useState({ openPopUp: false, chunksExists: false, @@ -113,7 +113,12 @@ const ChatContent: React.FC = ({ chatMessages }) => { isChatOnly={true} />
            -
            +
            = ({ chatMessages }) => { ); }; /** -* ChatOnlyComponent -* Wrapper component to provide necessary context and initialize chat functionality. -*/ + * ChatOnlyComponent + * Wrapper component to provide necessary context and initialize chat functionality. + */ const ChatOnlyComponent: React.FC = () => { const location = useLocation(); - const chatMessages = location.state?.messages as Messages[] || []; + const chatMessages = (location.state?.messages as Messages[]) || []; return ( @@ -146,4 +151,4 @@ const ChatOnlyComponent: React.FC = () => { ); }; -export default ChatOnlyComponent; \ No newline at end of file +export default ChatOnlyComponent; diff --git a/frontend/src/components/ChatBot/MultiModeMetrics.tsx b/frontend/src/components/ChatBot/MultiModeMetrics.tsx index 0ecae78c3..c97d917b2 100644 --- a/frontend/src/components/ChatBot/MultiModeMetrics.tsx +++ b/frontend/src/components/ChatBot/MultiModeMetrics.tsx @@ -48,7 +48,7 @@ export default function MultiModeMetrics({ footer: (info) => info.column.id, }), columnHelper.accessor((row) => row.answer_relevancy as number, { - id: 'Relevancy', + id: 'Answer Relevancy', cell: (info) => { return {info.getValue().toFixed(2)}; }, @@ -71,7 +71,7 @@ export default function MultiModeMetrics({ ), }), columnHelper.accessor((row) => row.faithfulness as number, { - id: 'Score', + id: 'Faithfullness', cell: (info) => { return {info.getValue().toFixed(2)}; }, @@ -94,7 +94,7 @@ export default function MultiModeMetrics({ ), }), columnHelper.accessor((row) => row.context_entity_recall_score as number, { - id: 'Recall Score', + id: 'Entity Recall Score', cell: (info) => { return {info.getValue()?.toFixed(2)}; }, diff --git a/frontend/src/components/Graph/GraphPropertiesPanel.tsx b/frontend/src/components/Graph/GraphPropertiesPanel.tsx index 006dfc095..a11399971 100644 --- a/frontend/src/components/Graph/GraphPropertiesPanel.tsx +++ b/frontend/src/components/Graph/GraphPropertiesPanel.tsx @@ -15,47 +15,47 @@ const GraphPropertiesPanel = ({ inspectedItem, newScheme }: GraphPropertiesPanel const filteredProperties = inspectedItemType === 'node' ? Object.entries((inspectedItem as BasicNode).properties) - .filter(([, value]) => value !== null && value !== undefined && value !== ' ') - .reduce((acc, [key, value]) => { - acc[key] = value; - return acc; - }, {} as Record) + .filter(([, value]) => value !== null && value !== undefined && value !== ' ') + .reduce((acc, [key, value]) => { + acc[key] = value; + return acc; + }, {} as Record) : {}; const properties = inspectedItemType === 'node' ? [ - { - key: '', - value: `${(inspectedItem as BasicNode).id}`, - type: 'String', - }, - ...Object.keys(filteredProperties).map((key) => { - const value = filteredProperties[key]; - return { key, value }; - }), - ] + { + key: '', + value: `${(inspectedItem as BasicNode).id}`, + type: 'String', + }, + ...Object.keys(filteredProperties).map((key) => { + const value = filteredProperties[key]; + return { key, value }; + }), + ] : [ - { - key: '', - value: `${(inspectedItem as BasicRelationship).id}`, - type: 'String', - }, - { - key: '', - value: `${(inspectedItem as BasicRelationship).from}`, - type: 'String', - }, - { - key: '', - value: `${(inspectedItem as BasicRelationship).to}`, - type: 'String', - }, - { - key: '', - value: `${(inspectedItem as BasicRelationship).caption ?? ''}`, - type: 'String', - }, - ]; + { + key: '', + value: `${(inspectedItem as BasicRelationship).id}`, + type: 'String', + }, + { + key: '', + value: `${(inspectedItem as BasicRelationship).from}`, + type: 'String', + }, + { + key: '', + value: `${(inspectedItem as BasicRelationship).to}`, + type: 'String', + }, + { + key: '', + value: `${(inspectedItem as BasicRelationship).caption ?? ''}`, + type: 'String', + }, + ]; const labelsSorted = useMemo(() => { if (isNode(inspectedItem)) { return [...inspectedItem.labels].sort(sortAlphabetically); diff --git a/frontend/src/components/Layout/Header.tsx b/frontend/src/components/Layout/Header.tsx index 36e4022f3..e537251db 100644 --- a/frontend/src/components/Layout/Header.tsx +++ b/frontend/src/components/Layout/Header.tsx @@ -61,7 +61,7 @@ const Header: React.FC = ({ chatOnly, deleteOnClick, setOpenConnecti const chatUrl = `/chat-only?uri=${encodeURIComponent( uri )}&user=${userName}&password=${encodedPassword}&database=${database}&port=${port}&connectionStatus=${connectionStatus}`; - navigate(chatUrl, { state: { messages, isLoading } });; + navigate(chatUrl, { state: { messages, isLoading } }); } else { const chatUrl = `/chat-only?openModal=true`; window.open(chatUrl, '_blank'); @@ -170,9 +170,17 @@ const Header: React.FC = ({ chatOnly, deleteOnClick, setOpenConnecti {buttonCaptions.connectToNeo4j} )} - {showBackButton && ( - - + {showBackButton && ( + + + )}
            = ({ chatOnly, deleteOnClick, setOpenConnecti text={tooltips.downloadChat} aria-label='Download Chat' clean - onClick={() => downloadClickHandler( - { conversation: messages }, - downloadLinkRef, - 'graph-builder-conversation.json' - )} + onClick={() => + downloadClickHandler( + { conversation: messages }, + downloadLinkRef, + 'graph-builder-conversation.json' + ) + } disabled={messages.length === 1 || getIsLoading(messages)} placement={chatOnly ? 'left' : 'bottom'} label={tooltips.downloadChat} > - + <> "" - + + Date: Fri, 22 Nov 2024 12:45:17 +0000 Subject: [PATCH 258/292] LLM_MODELS --- frontend/Dockerfile | 1 + frontend/nginx/nginx.prod.conf | 1 + 2 files changed, 2 insertions(+) diff --git a/frontend/Dockerfile b/frontend/Dockerfile index d0a258a59..066563b30 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -28,6 +28,7 @@ RUN VITE_BACKEND_API_URL=$VITE_BACKEND_API_URL \ VITE_LARGE_FILE_SIZE=${VITE_LARGE_FILE_SIZE} \ VITE_CHAT_MODES=$VITE_CHAT_MODES \ VITE_BATCH_SIZE=$VITE_BATCH_SIZE \ + VITE_LLM_MODELS=$VITE_LLM_MODELS \ VITE_LLM_MODELS_PROD=$VITE_LLM_MODELS_PROD \ yarn run build diff --git a/frontend/nginx/nginx.prod.conf b/frontend/nginx/nginx.prod.conf index ac6c1db82..f58585714 100644 --- a/frontend/nginx/nginx.prod.conf +++ b/frontend/nginx/nginx.prod.conf @@ -7,6 +7,7 @@ server { script-src 'self' 'unsafe-inline' https://accounts.google.com/gsi/client; default-src 'self' *.${VITE_FRONTEND_HOSTNAME} data:; style-src 'self' *.googleapis.com 'unsafe-inline';" always ; + gzip on; location / { root /usr/share/nginx/html; index index.html index.htm; From 33354f326b36c11805616d28417f5afd076e85ca Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Mon, 25 Nov 2024 18:01:30 +0530 Subject: [PATCH 259/292] re process feature state renaming (#898) * Status Change From Reprocess to Ready To Reprocess * Added the description * text changes --- backend/score.py | 2 +- backend/src/main.py | 2 +- docs/backend/backend_docs.adoc | 10 +++--- frontend/src/components/Content.tsx | 33 +++++++++++-------- frontend/src/components/FileTable.tsx | 4 +-- .../Popups/RetryConfirmation/Index.tsx | 7 +++- frontend/src/utils/Utils.ts | 4 +-- 7 files changed, 37 insertions(+), 25 deletions(-) diff --git a/backend/score.py b/backend/score.py index 44073be0c..6d4be0833 100644 --- a/backend/score.py +++ b/backend/score.py @@ -826,7 +826,7 @@ async def retry_processing(uri=Form(), userName=Form(), password=Form(), databas json_obj = {'api_name':'retry_processing', 'db_url':uri, 'userName':userName, 'database':database, 'file_name':file_name,'retry_condition':retry_condition, 'logging_time': formatted_time(datetime.now(timezone.utc)), 'elapsed_api_time':f'{elapsed_time:.2f}'} logger.log_struct(json_obj, "INFO") - return create_api_response('Success',message=f"Status set to Reprocess for filename : {file_name}") + return create_api_response('Success',message=f"Status set to Ready to Reprocess for filename : {file_name}") except Exception as e: job_status = "Failed" message="Unable to set status to Retry" diff --git a/backend/src/main.py b/backend/src/main.py index dc1cdd620..c5add5343 100644 --- a/backend/src/main.py +++ b/backend/src/main.py @@ -709,7 +709,7 @@ def populate_graph_schema_from_text(text, model, is_schema_description_cheked): def set_status_retry(graph, file_name, retry_condition): graphDb_data_Access = graphDBdataAccess(graph) obj_source_node = sourceNode() - status = "Reprocess" + status = "Ready to Reprocess" obj_source_node.file_name = file_name obj_source_node.status = status obj_source_node.retry_condition = retry_condition diff --git a/docs/backend/backend_docs.adoc b/docs/backend/backend_docs.adoc index 2591ac47e..d313a3402 100644 --- a/docs/backend/backend_docs.adoc +++ b/docs/backend/backend_docs.adoc @@ -923,14 +923,14 @@ The API is used to drop and create the vector index when vector index dimesion a POST /retry_processing ---- -This API is used to reprocess cancelled, completed or failed file sources. -Users have 3 options to reprocess files: +This API is used to Ready to Reprocess cancelled, completed or failed file sources. +Users have 3 options to Ready to Reprocess files: * Start from begnning - In this condition file will be processed from the begnning i.e. 1st chunk again. * Delete entities and start from begnning - If the file source is already processed and have any existing nodes and relations then those will be deleted and file will be reprocessed from the 1st chunk. * Start from last processed postion - Cancelled or failed files will be processed from the last successfully processed chunk position. This option is not available for completed files. -Ones the status is set to 'Reprocess', user can again click on Generate graph to process the file for knowledge graph creation. +Ones the status is set to 'Ready to Reprocess', user can again click on Generate graph to process the file for knowledge graph creation. **API Parameters :** @@ -938,7 +938,7 @@ Ones the status is set to 'Reprocess', user can again click on Generate graph to * `userName`= Neo4j db username, * `password`= Neo4j db password, * `database`= Neo4j database name, -* `file_name`= Name of the file which user want to reprocess. +* `file_name`= Name of the file which user want to Ready to Reprocess. * `retry_condition` = One of the above 3 conditions which is selected for reprocessing. @@ -947,7 +947,7 @@ Ones the status is set to 'Reprocess', user can again click on Generate graph to .... { "status": "Success", - "message": "Status set to Reprocess for filename : $filename" + "message": "Status set to Ready to Reprocess for filename : $filename" } .... diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 97e2dcde6..12b0705bf 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -261,7 +261,9 @@ const Content: React.FC = ({ return { ...curfile, model: - curfile.status === 'New' || curfile.status === 'Reprocess' ? selectedOption?.value ?? '' : curfile.model, + curfile.status === 'New' || curfile.status === 'Ready to Reprocess' + ? selectedOption?.value ?? '' + : curfile.model, }; }); }); @@ -416,7 +418,7 @@ const Content: React.FC = ({ showNormalToast(`Processing ${batch.length} files at a time.`); for (let i = 0; i < batch.length; i++) { if (newCheck) { - if (batch[i]?.status === 'New' || batch[i].status === 'Reprocess') { + if (batch[i]?.status === 'New' || batch[i].status === 'Ready to Reprocess') { data.push(extractData(batch[i].id, isSelectedFiles, selectedFiles as CustomFile[])); } } else { @@ -537,7 +539,7 @@ const Content: React.FC = ({ } else { const selectedNewFiles = childRef.current ?.getSelectedRows() - .filter((f) => f.status === 'New' || f.status == 'Reprocess'); + .filter((f) => f.status === 'New' || f.status == 'Ready to Reprocess'); addFilesToQueue(selectedNewFiles as CustomFile[]); } }; @@ -593,7 +595,7 @@ const Content: React.FC = ({ return f.name === filename ? { ...f, - status: 'Reprocess', + status: 'Ready to Reprocess', processingProgress: isStartFromBegining ? 0 : f.processingProgress, nodesCount: isStartFromBegining ? 0 : f.nodesCount, relationshipsCount: isStartFromBegining ? 0 : f.relationshipsCount, @@ -621,7 +623,8 @@ const Content: React.FC = ({ ); const newFilecheck = useMemo( - () => childRef.current?.getSelectedRows().filter((f) => f.status === 'New' || f.status == 'Reprocess').length, + () => + childRef.current?.getSelectedRows().filter((f) => f.status === 'New' || f.status == 'Ready to Reprocess').length, [childRef.current?.getSelectedRows()] ); @@ -631,7 +634,7 @@ const Content: React.FC = ({ ); const dropdowncheck = useMemo( - () => !filesData.some((f) => f.status === 'New' || f.status === 'Waiting' || f.status === 'Reprocess'), + () => !filesData.some((f) => f.status === 'New' || f.status === 'Waiting' || f.status === 'Ready to Reprocess'), [filesData] ); @@ -651,12 +654,12 @@ const Content: React.FC = ({ if (selectedRows?.length) { for (let index = 0; index < selectedRows.length; index++) { const parsedFile: CustomFile = selectedRows[index]; - if (parsedFile.status === 'New' || parsedFile.status == 'Reprocess') { + if (parsedFile.status === 'New' || parsedFile.status == 'Ready to Reprocess') { newstatusfiles.push(parsedFile); } } } else if (filesData.length) { - newstatusfiles = filesData.filter((f) => f.status === 'New' || f.status === 'Reprocess'); + newstatusfiles = filesData.filter((f) => f.status === 'New' || f.status === 'Ready to Reprocess'); } return newstatusfiles; }, [filesData, childRef.current?.getSelectedRows()]); @@ -708,7 +711,7 @@ const Content: React.FC = ({ if ( parsedData.fileSource === 'local file' && typeof parsedData.size === 'number' && - (parsedData.status === 'New' || parsedData.status == 'Reprocess') && + (parsedData.status === 'New' || parsedData.status == 'Ready to Reprocess') && parsedData.size > largeFileSize ) { selectedLargeFiles.push(parsedData); @@ -717,16 +720,20 @@ const Content: React.FC = ({ if (selectedLargeFiles.length) { setshowConfirmationModal(true); } else { - handleGenerateGraph(selectedRows.filter((f) => f.status === 'New' || f.status === 'Reprocess')); + handleGenerateGraph(selectedRows.filter((f) => f.status === 'New' || f.status === 'Ready to Reprocess')); } } else if (filesData.length) { const largefiles = filesData.filter((f) => { - if (typeof f.size === 'number' && (f.status === 'New' || f.status == 'Reprocess') && f.size > largeFileSize) { + if ( + typeof f.size === 'number' && + (f.status === 'New' || f.status == 'Ready to Reprocess') && + f.size > largeFileSize + ) { return true; } return false; }); - const selectAllNewFiles = filesData.filter((f) => f.status === 'New' || f.status === 'Reprocess'); + const selectAllNewFiles = filesData.filter((f) => f.status === 'New' || f.status === 'Ready to Reprocess'); const stringified = selectAllNewFiles.reduce((accu, f) => { const key = f.id; // @ts-ignore @@ -737,7 +744,7 @@ const Content: React.FC = ({ if (largefiles.length) { setshowConfirmationModal(true); } else { - handleGenerateGraph(filesData.filter((f) => f.status === 'New' || f.status === 'Reprocess')); + handleGenerateGraph(filesData.filter((f) => f.status === 'New' || f.status === 'Ready to Reprocess')); } } }; diff --git a/frontend/src/components/FileTable.tsx b/frontend/src/components/FileTable.tsx index 22f48c119..f02e7fb7f 100644 --- a/frontend/src/components/FileTable.tsx +++ b/frontend/src/components/FileTable.tsx @@ -173,9 +173,9 @@ const FileTable = forwardRef((props, ref) => { onRetry(info?.row?.id as string)} > diff --git a/frontend/src/components/Popups/RetryConfirmation/Index.tsx b/frontend/src/components/Popups/RetryConfirmation/Index.tsx index 5112ca688..379be9598 100644 --- a/frontend/src/components/Popups/RetryConfirmation/Index.tsx +++ b/frontend/src/components/Popups/RetryConfirmation/Index.tsx @@ -29,6 +29,9 @@ function RetryConfirmationDialog({ return ( Reprocess Options + + Clicking "Continue" will mark these files as "Ready to Reprocess." To proceed, click “Generate Graph” to start the reprocessing process. + {alertStatus.showAlert && ( @@ -69,7 +72,9 @@ function RetryConfirmationDialog({ { diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index beba5e3d1..7314c55e7 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -69,7 +69,7 @@ export const statusCheck = (status: string) => { return 'danger'; case 'Upload Failed': return 'danger'; - case 'Reprocess': + case 'Ready to Reprocess': return 'info'; default: return 'unknown'; @@ -378,7 +378,7 @@ export const getFileSourceStatus = (item: SourceNode) => { if (item?.fileSource === 'local file') { return item?.status; } - if (item?.status === 'Completed' || item.status === 'Failed' || item.status === 'Reprocess') { + if (item?.status === 'Completed' || item.status === 'Failed' || item.status === 'Ready to Reprocess') { return item?.status; } if ( From 9e8ffca977b450c21667ceddba74288e4e87a18d Mon Sep 17 00:00:00 2001 From: kaustubh-darekar Date: Mon, 25 Nov 2024 20:06:38 +0530 Subject: [PATCH 260/292] Community Counts after post processing (#890) * Community count updated in post processing api * Community count query changed * API integration for communities post counts * node and relationships count * filename check * show communities in popover only if its GDS * Code segregation --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> --- backend/score.py | 9 +- backend/src/shared/constants.py | 144 ++++++++++--------- frontend/src/components/BreakDownPopOver.tsx | 33 +++++ frontend/src/components/Content.tsx | 70 ++++++++- frontend/src/components/FileTable.tsx | 34 +---- frontend/src/components/UI/CustomPopOver.tsx | 15 ++ 6 files changed, 199 insertions(+), 106 deletions(-) create mode 100644 frontend/src/components/BreakDownPopOver.tsx create mode 100644 frontend/src/components/UI/CustomPopOver.tsx diff --git a/backend/score.py b/backend/score.py index 6d4be0833..ac2468066 100644 --- a/backend/score.py +++ b/backend/score.py @@ -317,6 +317,7 @@ async def post_processing(uri=Form(), userName=Form(), password=Form(), database try: graph = create_graph_database_connection(uri, userName, password, database) tasks = set(map(str.strip, json.loads(tasks))) + count_response = "" start = time.time() if "materialize_text_chunk_similarities" in tasks: await asyncio.to_thread(update_graph, graph) @@ -342,12 +343,14 @@ async def post_processing(uri=Form(), userName=Form(), password=Form(), database graphDb_data_Access = graphDBdataAccess(graph) document_name = "" count_response = graphDb_data_Access.update_node_relationship_count(document_name) - logging.info(f'Updated source node with community related counts') + if count_response: + count_response = [{"filename": filename, **counts} for filename, counts in count_response.items()] + logging.info(f'Updated source node with community related counts') end = time.time() elapsed_time = end - start json_obj = {'api_name': api_name, 'db_url': uri, 'userName':userName, 'database':database, 'tasks':tasks, 'logging_time': formatted_time(datetime.now(timezone.utc)), 'elapsed_api_time':f'{elapsed_time:.2f}'} - logger.log_struct(json_obj) - return create_api_response('Success', message='All tasks completed successfully') + # logger.log_struct(json_obj) + return create_api_response('Success', data=count_response, message='All tasks completed successfully') except Exception as e: job_status = "Failed" diff --git a/backend/src/shared/constants.py b/backend/src/shared/constants.py index 2bb7848ee..bf96532d9 100644 --- a/backend/src/shared/constants.py +++ b/backend/src/shared/constants.py @@ -175,83 +175,89 @@ """ NODEREL_COUNT_QUERY_WITH_COMMUNITY = """ -MATCH docs = (d:Document) +MATCH (d:Document) WHERE d.fileName IS NOT NULL -CALL (d) { - OPTIONAL MATCH (d)<-[po:PART_OF]-(c:Chunk) - OPTIONAL MATCH (c)-[he:HAS_ENTITY]->(e:__Entity__) - OPTIONAL MATCH (c)-[sim:SIMILAR]->(c2:Chunk) - OPTIONAL MATCH (c)-[nc:NEXT_CHUNK]->(c3:Chunk) - WITH d, count(distinct c) AS chunkNodeCount, - count(distinct po) AS partOfRelCount, - count(distinct he) AS hasEntityRelCount, - count(distinct sim) AS similarRelCount, - count(distinct nc) AS nextChunkRelCount, - count(distinct e) AS entityNodeCount, - collect(distinct e) AS entities - CALL (entities) { - UNWIND entities AS e - RETURN sum(COUNT { (e)-->(e2:__Entity__) WHERE e2 in entities }) AS entityEntityRelCount - } - CALL (entities) { - UNWIND entities AS e - OPTIONAL MATCH (e)-[ic:IN_COMMUNITY]->(comm:__Community__) - WITH collect(distinct comm) AS base_communities, collect(distinct ic) AS inCommunityRels - // Step 2: Find first-level parents and relationships - UNWIND base_communities AS base_comm - OPTIONAL MATCH (base_comm)-[pc1:PARENT_COMMUNITY]->(first_level:__Community__) - WITH base_communities, inCommunityRels, collect(distinct first_level) AS first_level_parents, - collect(distinct pc1) AS parentCommunityRels1 - // Step 3: Find second-level parents and relationships - UNWIND first_level_parents AS first_level - OPTIONAL MATCH (first_level)-[pc2:PARENT_COMMUNITY]->(second_level:__Community__) - WITH base_communities, inCommunityRels, first_level_parents, parentCommunityRels1, - collect(distinct second_level) AS second_level_parents, collect(distinct pc2) AS parentCommunityRels2 - // Step 4: Find third-level parents and relationships - UNWIND second_level_parents AS second_level - OPTIONAL MATCH (second_level)-[pc3:PARENT_COMMUNITY]->(third_level:__Community__) - WITH base_communities, inCommunityRels, first_level_parents, second_level_parents, parentCommunityRels1, parentCommunityRels2, - collect(distinct third_level) AS third_level_parents, collect(distinct pc3) AS parentCommunityRels3 - // Aggregate all communities and relationships - WITH - base_communities + coalesce(first_level_parents, []) + coalesce(second_level_parents, []) + coalesce(third_level_parents, []) AS all_communities, - inCommunityRels + coalesce(parentCommunityRels1, []) + coalesce(parentCommunityRels2, []) + coalesce(parentCommunityRels3, []) AS all_rels - RETURN size(all_communities) AS communityNodeCount, size(all_rels) AS communityRelCount - } - RETURN d.fileName AS filename, chunkNodeCount, - partOfRelCount + hasEntityRelCount + similarRelCount + nextChunkRelCount AS chunkRelCount, - entityNodeCount, entityEntityRelCount, communityNodeCount, communityRelCount +OPTIONAL MATCH (d)<-[po:PART_OF]-(c:Chunk) +OPTIONAL MATCH (c)-[he:HAS_ENTITY]->(e:__Entity__) +OPTIONAL MATCH (c)-[sim:SIMILAR]->(c2:Chunk) +OPTIONAL MATCH (c)-[nc:NEXT_CHUNK]->(c3:Chunk) +OPTIONAL MATCH (e)-[ic:IN_COMMUNITY]->(comm:__Community__) +OPTIONAL MATCH (comm)-[pc1:PARENT_COMMUNITY]->(first_level:__Community__) +OPTIONAL MATCH (first_level)-[pc2:PARENT_COMMUNITY]->(second_level:__Community__) +OPTIONAL MATCH (second_level)-[pc3:PARENT_COMMUNITY]->(third_level:__Community__) +WITH + d.fileName AS filename, + count(DISTINCT c) AS chunkNodeCount, + count(DISTINCT po) AS partOfRelCount, + count(DISTINCT he) AS hasEntityRelCount, + count(DISTINCT sim) AS similarRelCount, + count(DISTINCT nc) AS nextChunkRelCount, + count(DISTINCT e) AS entityNodeCount, + collect(DISTINCT e) AS entities, + count(DISTINCT comm) AS baseCommunityCount, + count(DISTINCT first_level) AS firstlevelcommCount, + count(DISTINCT second_level) AS secondlevelcommCount, + count(DISTINCT third_level) AS thirdlevelcommCount, + count(DISTINCT ic) AS inCommunityCount, + count(DISTINCT pc1) AS parentCommunityRelCount1, + count(DISTINCT pc2) AS parentCommunityRelCount2, + count(DISTINCT pc3) AS parentCommunityRelCount3 +WITH + filename, + chunkNodeCount, + partOfRelCount + hasEntityRelCount + similarRelCount + nextChunkRelCount AS chunkRelCount, + entityNodeCount, + entities, + baseCommunityCount + firstlevelcommCount + secondlevelcommCount + thirdlevelcommCount AS commCount, + inCommunityCount + parentCommunityRelCount1 + parentCommunityRelCount2 + parentCommunityRelCount3 AS communityRelCount +CALL (entities) { + UNWIND entities AS e + RETURN sum(COUNT { (e)-->(e2:__Entity__) WHERE e2 in entities }) AS entityEntityRelCount } -RETURN filename, chunkNodeCount, chunkRelCount, entityNodeCount, entityEntityRelCount, communityNodeCount, communityRelCount -ORDER BY d.createdAt DESC +RETURN + filename, + COALESCE(chunkNodeCount, 0) AS chunkNodeCount, + COALESCE(chunkRelCount, 0) AS chunkRelCount, + COALESCE(entityNodeCount, 0) AS entityNodeCount, + COALESCE(entityEntityRelCount, 0) AS entityEntityRelCount, + COALESCE(commCount, 0) AS communityNodeCount, + COALESCE(communityRelCount, 0) AS communityRelCount """ NODEREL_COUNT_QUERY_WITHOUT_COMMUNITY = """ -MATCH docs = (d:Document) +MATCH (d:Document) WHERE d.fileName = $document_name -CALL (d) { - OPTIONAL MATCH (d)<-[po:PART_OF]-(c:Chunk) - OPTIONAL MATCH (c)-[he:HAS_ENTITY]->(e:__Entity__) - OPTIONAL MATCH (c)-[sim:SIMILAR]->(c2:Chunk) - OPTIONAL MATCH (c)-[nc:NEXT_CHUNK]->(c3:Chunk) - WITH d, count(distinct c) AS chunkNodeCount, - count(distinct po) AS partOfRelCount, - count(distinct he) AS hasEntityRelCount, - count(distinct sim) AS similarRelCount, - count(distinct nc) AS nextChunkRelCount, - count(distinct e) AS entityNodeCount, - collect(distinct e) AS entities - CALL (entities) { - UNWIND entities AS e - RETURN sum(COUNT { (e)-->(e2:__Entity__) WHERE e2 in entities }) AS entityEntityRelCount - } - RETURN d.fileName AS filename, chunkNodeCount, - partOfRelCount + hasEntityRelCount + similarRelCount + nextChunkRelCount AS chunkRelCount, - entityNodeCount, entityEntityRelCount +OPTIONAL MATCH (d)<-[po:PART_OF]-(c:Chunk) +OPTIONAL MATCH (c)-[he:HAS_ENTITY]->(e:__Entity__) +OPTIONAL MATCH (c)-[sim:SIMILAR]->(c2:Chunk) +OPTIONAL MATCH (c)-[nc:NEXT_CHUNK]->(c3:Chunk) +WITH + d.fileName AS filename, + count(DISTINCT c) AS chunkNodeCount, + count(DISTINCT po) AS partOfRelCount, + count(DISTINCT he) AS hasEntityRelCount, + count(DISTINCT sim) AS similarRelCount, + count(DISTINCT nc) AS nextChunkRelCount, + count(DISTINCT e) AS entityNodeCount, + collect(DISTINCT e) AS entities +WITH + filename, + chunkNodeCount, + partOfRelCount + hasEntityRelCount + similarRelCount + nextChunkRelCount AS chunkRelCount, + entityNodeCount, + entities +CALL (entities) { + UNWIND entities AS e + RETURN sum(COUNT { (e)-->(e2:__Entity__) WHERE e2 in entities }) AS entityEntityRelCount } -RETURN filename, chunkNodeCount, chunkRelCount, entityNodeCount, entityEntityRelCount -ORDER BY d.createdAt DESC +RETURN + filename, + COALESCE(chunkNodeCount, 0) AS chunkNodeCount, + COALESCE(chunkRelCount, 0) AS chunkRelCount, + COALESCE(entityNodeCount, 0) AS entityNodeCount, + COALESCE(entityEntityRelCount, 0) AS entityEntityRelCount """ + ## CHAT SETUP CHAT_MAX_TOKENS = 1000 CHAT_SEARCH_KWARG_SCORE_THRESHOLD = 0.5 diff --git a/frontend/src/components/BreakDownPopOver.tsx b/frontend/src/components/BreakDownPopOver.tsx new file mode 100644 index 000000000..4905497e3 --- /dev/null +++ b/frontend/src/components/BreakDownPopOver.tsx @@ -0,0 +1,33 @@ +import CustomPopOver from './UI/CustomPopOver'; +import { IconButton } from '@neo4j-ndl/react'; +import { InformationCircleIconOutline } from '@neo4j-ndl/react/icons'; +import { CustomFileBase } from '../types'; +import { useCredentials } from '../context/UserCredentials'; + +export default function BreakDownPopOver({ file, isNodeCount = true }: { file: CustomFileBase; isNodeCount: boolean }) { + const { isGdsActive } = useCredentials(); + + return ( + + + + } + > + {isNodeCount ? ( +
              +
            • Chunk Nodes: {file.chunkNodeCount}
            • +
            • Entity Nodes: {file.entityNodeCount}
            • + {isGdsActive &&
            • Community Nodes: {file.communityNodeCount}
            • } +
            + ) : ( +
              +
            • Chunk Relations: {file.chunkRelCount}
            • +
            • Entity Relations: {file.entityEntityRelCount}
            • + {isGdsActive &&
            • Community Relations: {file.communityRelCount}
            • } +
            + )} +
            + ); +} diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 12b0705bf..552dc9506 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -177,8 +177,39 @@ const Content: React.FC = ({ if (processedCount === 1 && queue.isEmpty()) { (async () => { showNormalToast(); - await postProcessing(userCredentials as UserCredentials, postProcessingTasks); - showSuccessToast('All Q&A functionality is available now.'); + try { + const response = await postProcessing(userCredentials as UserCredentials, postProcessingTasks); + if (response.data.status === 'Success') { + const communityfiles = response.data.data; + communityfiles.forEach((c: any) => { + setFilesData((prev) => { + return prev.map((f) => { + if (f.name === c.filename) { + return { + ...f, + chunkNodeCount: c.chunkNodeCount ?? 0, + entityNodeCount: c.entityNodeCount ?? 0, + communityNodeCount: c.communityNodeCount ?? 0, + chunkRelCount: c.chunkRelCount ?? 0, + entityEntityRelCount: c.entityEntityRelCount ?? 0, + communityRelCount: c.communityRelCount ?? 0, + nodesCount: c.nodeCount, + relationshipsCount: c.relationshipCount, + }; + } + return f; + }); + }); + }); + showSuccessToast('All Q&A functionality is available now.'); + } else { + throw new Error(response.data.error); + } + } catch (error) { + if (error instanceof Error) { + showSuccessToast(error.message); + } + } })(); } }, [processedCount, userCredentials, queue, isReadOnlyUser, isGdsActive]); @@ -431,8 +462,39 @@ const Content: React.FC = ({ const addFilesToQueue = async (remainingFiles: CustomFile[]) => { if (!remainingFiles.length) { showNormalToast(); - await postProcessing(userCredentials as UserCredentials, postProcessingTasks); - showSuccessToast('All Q&A functionality is available now.'); + try { + const response = await postProcessing(userCredentials as UserCredentials, postProcessingTasks); + if (response.data.status === 'Success') { + const communityfiles = response.data.data; + communityfiles.forEach((c: any) => { + setFilesData((prev) => { + return prev.map((f) => { + if (f.name === c.filename) { + return { + ...f, + chunkNodeCount: c.chunkNodeCount ?? 0, + entityNodeCount: c.entityNodeCount ?? 0, + communityNodeCount: c.communityNodeCount ?? 0, + chunkRelCount: c.chunkRelCount ?? 0, + entityEntityRelCount: c.entityEntityRelCount ?? 0, + communityRelCount: c.communityRelCount ?? 0, + nodesCount: c.nodeCount, + relationshipsCount: c.relationshipCount, + }; + } + return f; + }); + }); + }); + showSuccessToast('All Q&A functionality is available now.'); + } else { + throw new Error(response.data.error); + } + } catch (error) { + if (error instanceof Error) { + showSuccessToast(error.message); + } + } } for (let index = 0; index < remainingFiles.length; index++) { const f = remainingFiles[index]; diff --git a/frontend/src/components/FileTable.tsx b/frontend/src/components/FileTable.tsx index f02e7fb7f..53903d032 100644 --- a/frontend/src/components/FileTable.tsx +++ b/frontend/src/components/FileTable.tsx @@ -3,7 +3,6 @@ import { DataGridComponents, Flex, IconButton, - Popover, ProgressBar, StatusIndicator, TextLink, @@ -42,7 +41,6 @@ import { ClipboardDocumentIconSolid, MagnifyingGlassCircleIconSolid, DocumentTextIconSolid, - InformationCircleIconOutline, } from '@neo4j-ndl/react/icons'; import CustomProgressBar from './UI/CustomProgressBar'; import subscribe from '../services/PollingAPI'; @@ -55,6 +53,7 @@ import { IconButtonWithToolTip } from './UI/IconButtonToolTip'; import { batchSize, largeFileSize, llms } from '../utils/Constants'; import { showErrorToast, showNormalToast } from '../utils/toasts'; import { ThemeWrapperContext } from '../context/ThemeWrapper'; +import BreakDownPopOver from './BreakDownPopOver'; let onlyfortheFirstRender = true; @@ -513,25 +512,13 @@ const FileTable = forwardRef((props, ref) => { info.row.original.chunkNodeCount > 0 || info.row.original.communityNodeCount > 0 || info.row.original.entityNodeCount > 0; + return ( {info.getValue()} {hasNodeBreakDownValues && (info.row.original.status === 'Completed' || info.row.original.status === 'Failed') && ( - - - - - - - -
              -
            • Chunk Nodes: {info.row.original.chunkNodeCount}
            • -
            • Entity Nodes: {info.row.original.entityNodeCount}
            • -
            • Community Nodes: {info.row.original.communityNodeCount}
            • -
            -
            -
            + )}
            ); @@ -551,20 +538,7 @@ const FileTable = forwardRef((props, ref) => { {info.getValue()} {hasRelationsBreakDownValues && (info.row.original.status === 'Completed' || info.row.original.status === 'Failed') && ( - - - - - - - -
              -
            • Chunk Relations: {info.row.original.chunkRelCount}
            • -
            • Entity Relations: {info.row.original.entityEntityRelCount}
            • -
            • Community Relations: {info.row.original.communityRelCount}
            • -
            -
            -
            + )} ); diff --git a/frontend/src/components/UI/CustomPopOver.tsx b/frontend/src/components/UI/CustomPopOver.tsx new file mode 100644 index 000000000..a15a9d36b --- /dev/null +++ b/frontend/src/components/UI/CustomPopOver.tsx @@ -0,0 +1,15 @@ +import { Popover } from '@neo4j-ndl/react'; +import { FunctionComponent, ReactNode } from 'react'; +type Props = { + children: ReactNode; + Trigger: ReactNode; +}; +const CustomPopOver: FunctionComponent = ({ children, Trigger }) => { + return ( + + {Trigger} + {children} + + ); +}; +export default CustomPopOver; From 8af533cd149f7534b5dccb6dd8f6d5969a27bf34 Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Mon, 25 Nov 2024 20:07:05 +0530 Subject: [PATCH 261/292] format and checked fixes (#897) --- frontend/src/components/ChatBot/Chatbot.tsx | 12 ++++++------ .../Deduplication/index.tsx | 4 ++-- .../SelectedJobList.tsx | 4 ++-- .../PostProcessingCheckList/index.tsx | 11 ++++------- frontend/src/context/UsersFiles.tsx | 19 ++++++++++++------- frontend/src/utils/Utils.ts | 2 +- 6 files changed, 27 insertions(+), 25 deletions(-) diff --git a/frontend/src/components/ChatBot/Chatbot.tsx b/frontend/src/components/ChatBot/Chatbot.tsx index 03d027d04..97efb8058 100644 --- a/frontend/src/components/ChatBot/Chatbot.tsx +++ b/frontend/src/components/ChatBot/Chatbot.tsx @@ -249,7 +249,7 @@ const Chatbot: FC = (props) => { } else { setListMessages((prev) => prev.map((msg) => - (msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg) + msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg ) ); } @@ -264,7 +264,7 @@ const Chatbot: FC = (props) => { } else { setListMessages((prev) => prev.map((msg) => - (msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg) + msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg ) ); } @@ -273,7 +273,7 @@ const Chatbot: FC = (props) => { console.error(`API call failed for mode ${mode}:`, result.reason); setListMessages((prev) => prev.map((msg) => - (msg.id === chatbotMessageId + msg.id === chatbotMessageId ? { ...msg, modes: { @@ -281,7 +281,7 @@ const Chatbot: FC = (props) => { [mode]: { message: 'Failed to fetch response for this mode.', error: result.reason }, }, } - : msg) + : msg ) ); } @@ -294,7 +294,7 @@ const Chatbot: FC = (props) => { if (error instanceof Error) { setListMessages((prev) => prev.map((msg) => - (msg.id === chatbotMessageId + msg.id === chatbotMessageId ? { ...msg, isLoading: false, @@ -306,7 +306,7 @@ const Chatbot: FC = (props) => { }, }, } - : msg) + : msg ) ); } diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx index 97c584b7c..f1d469cf2 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx @@ -104,12 +104,12 @@ export default function DeduplicationTab() { const onRemove = (nodeid: string, similarNodeId: string) => { setDuplicateNodes((prev) => { return prev.map((d) => - (d.e.elementId === nodeid + d.e.elementId === nodeid ? { ...d, similar: d.similar.filter((n) => n.elementId != similarNodeId), } - : d) + : d ); }); }; diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx index 447b1f846..fc5f39206 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx @@ -11,11 +11,11 @@ export default function SelectedJobList({ }) { const ongoingPostProcessingTasks = useMemo( () => - (isGdsActive + isGdsActive ? postProcessingTasks.includes('enable_communities') ? postProcessingTasks : postProcessingTasks.filter((s) => s != 'enable_communities') - : postProcessingTasks.filter((s) => s != 'enable_communities')), + : postProcessingTasks.filter((s) => s != 'enable_communities'), [isGdsActive, postProcessingTasks] ); return ( diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/index.tsx index d5ebc04a2..d2b721995 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/index.tsx @@ -9,6 +9,9 @@ export default function PostProcessingCheckList() { const tablet = useMediaQuery(`(min-width:${breakpoints.xs}) and (max-width: ${breakpoints.lg})`); const { postProcessingTasks, setPostProcessingTasks } = useFileContext(); const { isGdsActive } = useCredentials(); + const handleCheckboxChange = (jobTitle: string, isChecked: boolean) => { + setPostProcessingTasks((prev) => (isChecked ? [...prev, jobTitle] : prev.filter((task) => task !== jobTitle))); + }; return (
            @@ -37,14 +40,8 @@ export default function PostProcessingCheckList() { ? isGdsActive && postProcessingTasks.includes(job.title) : postProcessingTasks.includes(job.title) } - onChange={(e) => { - if (e.target.checked) { - setPostProcessingTasks((prev) => [...prev, job.title]); - } else { - setPostProcessingTasks((prev) => prev.filter((s) => s !== job.title)); - } - }} isDisabled={isCreateCommunities && !isGdsActive} + onChange={(e) => handleCheckboxChange(job.title, e.target.checked)} ariaLabel='checkbox-postProcessing' /> {job.description} diff --git a/frontend/src/context/UsersFiles.tsx b/frontend/src/context/UsersFiles.tsx index 25f031f95..92f4a4b77 100644 --- a/frontend/src/context/UsersFiles.tsx +++ b/frontend/src/context/UsersFiles.tsx @@ -16,7 +16,7 @@ const FileContextProvider: FC = ({ children }) => { const selectedNodeLabelstr = localStorage.getItem('selectedNodeLabels'); const selectedNodeRelsstr = localStorage.getItem('selectedRelationshipLabels'); const persistedQueue = localStorage.getItem('waitingQueue'); - const { userCredentials } = useCredentials(); + const { userCredentials, isGdsActive } = useCredentials(); const [files, setFiles] = useState<(File | null)[] | []>([]); const [filesData, setFilesData] = useState([]); const [queue, setQueue] = useState( @@ -35,12 +35,17 @@ const FileContextProvider: FC = ({ children }) => { triggeredFrom: '', show: false, }); - const [postProcessingTasks, setPostProcessingTasks] = useState([ - 'materialize_text_chunk_similarities', - 'enable_hybrid_search_and_fulltext_search_in_bloom', - 'materialize_entity_similarities', - 'enable_communities', - ]); + const [postProcessingTasks, setPostProcessingTasks] = useState(() => { + const tasks = [ + 'materialize_text_chunk_similarities', + 'enable_hybrid_search_and_fulltext_search_in_bloom', + 'materialize_entity_similarities', + ]; + if (isGdsActive) { + tasks.push('enable_communities'); + } + return tasks; + }); const [processedCount, setProcessedCount] = useState(0); const [postProcessingVal, setPostProcessingVal] = useState(false); diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index 7314c55e7..82217535d 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -395,7 +395,7 @@ export const isFileCompleted = (waitingFile: CustomFile, item: SourceNode) => waitingFile && item.status === 'Completed'; export const calculateProcessedCount = (prev: number, batchSize: number) => - (prev === batchSize ? batchSize - 1 : prev + 1); + prev === batchSize ? batchSize - 1 : prev + 1; export const isProcessingFileValid = (item: SourceNode, userCredentials: UserCredentials) => { return item.status === 'Processing' && item.fileName != undefined && userCredentials && userCredentials.database; From 4e203840b6703242930ac4837a80f6d9bbfe96bd Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Tue, 26 Nov 2024 10:08:17 +0530 Subject: [PATCH 262/292] added info to show 50 chunks processing (#899) --- .../src/components/Graph/GraphViewModal.tsx | 23 ++++++++++++------- frontend/src/utils/Constants.ts | 1 + 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/frontend/src/components/Graph/GraphViewModal.tsx b/frontend/src/components/Graph/GraphViewModal.tsx index 4fe1f52f5..af5a7a90a 100644 --- a/frontend/src/components/Graph/GraphViewModal.tsx +++ b/frontend/src/components/Graph/GraphViewModal.tsx @@ -17,6 +17,7 @@ import type { Node, Relationship } from '@neo4j-nvl/base'; import { ArrowPathIconOutline, FitToScreenIcon, + InformationCircleIconOutline, MagnifyingGlassMinusIconOutline, MagnifyingGlassPlusIconOutline, } from '@neo4j-ndl/react/icons'; @@ -62,10 +63,10 @@ const GraphViewModal: React.FunctionComponent = ({ graphType.includes('DocumentChunk') && graphType.includes('Entities') ? queryMap.DocChunkEntities : graphType.includes('DocumentChunk') - ? queryMap.DocChunks - : graphType.includes('Entities') - ? queryMap.Entities - : ''; + ? queryMap.DocChunks + : graphType.includes('Entities') + ? queryMap.Entities + : ''; // fit graph to original position const handleZoomToFit = () => { @@ -107,10 +108,10 @@ const GraphViewModal: React.FunctionComponent = ({ const nodeRelationshipData = viewPoint === graphLabels.showGraphView ? await graphQueryAPI( - userCredentials as UserCredentials, - graphQuery, - selectedRows?.map((f) => f.name) - ) + userCredentials as UserCredentials, + graphQuery, + selectedRows?.map((f) => f.name) + ) : await graphQueryAPI(userCredentials as UserCredentials, graphQuery, [inspectedName ?? '']); return nodeRelationshipData; } catch (error: any) { @@ -348,6 +349,12 @@ const GraphViewModal: React.FunctionComponent = ({ > {headerTitle} + {viewPoint !== graphLabels.chatInfoView && (
            + + + + {graphLabels.chunksInfo} +
            )} {checkBoxView && ( Date: Tue, 26 Nov 2024 04:53:43 +0000 Subject: [PATCH 263/292] format and lint fixes --- frontend/src/components/BreakDownPopOver.tsx | 2 +- frontend/src/components/ChatBot/Chatbot.tsx | 12 ++++---- .../src/components/Graph/GraphViewModal.tsx | 30 ++++++++++--------- .../Deduplication/index.tsx | 4 +-- .../SelectedJobList.tsx | 4 +-- .../Popups/RetryConfirmation/Index.tsx | 3 +- frontend/src/utils/Constants.ts | 2 +- frontend/src/utils/Utils.ts | 2 +- 8 files changed, 31 insertions(+), 28 deletions(-) diff --git a/frontend/src/components/BreakDownPopOver.tsx b/frontend/src/components/BreakDownPopOver.tsx index 4905497e3..01ebc4f20 100644 --- a/frontend/src/components/BreakDownPopOver.tsx +++ b/frontend/src/components/BreakDownPopOver.tsx @@ -22,7 +22,7 @@ export default function BreakDownPopOver({ file, isNodeCount = true }: { file: C {isGdsActive &&
          3. Community Nodes: {file.communityNodeCount}
          4. }
      ) : ( -
        +
        • Chunk Relations: {file.chunkRelCount}
        • Entity Relations: {file.entityEntityRelCount}
        • {isGdsActive &&
        • Community Relations: {file.communityRelCount}
        • } diff --git a/frontend/src/components/ChatBot/Chatbot.tsx b/frontend/src/components/ChatBot/Chatbot.tsx index 97efb8058..03d027d04 100644 --- a/frontend/src/components/ChatBot/Chatbot.tsx +++ b/frontend/src/components/ChatBot/Chatbot.tsx @@ -249,7 +249,7 @@ const Chatbot: FC = (props) => { } else { setListMessages((prev) => prev.map((msg) => - msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg + (msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg) ) ); } @@ -264,7 +264,7 @@ const Chatbot: FC = (props) => { } else { setListMessages((prev) => prev.map((msg) => - msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg + (msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg) ) ); } @@ -273,7 +273,7 @@ const Chatbot: FC = (props) => { console.error(`API call failed for mode ${mode}:`, result.reason); setListMessages((prev) => prev.map((msg) => - msg.id === chatbotMessageId + (msg.id === chatbotMessageId ? { ...msg, modes: { @@ -281,7 +281,7 @@ const Chatbot: FC = (props) => { [mode]: { message: 'Failed to fetch response for this mode.', error: result.reason }, }, } - : msg + : msg) ) ); } @@ -294,7 +294,7 @@ const Chatbot: FC = (props) => { if (error instanceof Error) { setListMessages((prev) => prev.map((msg) => - msg.id === chatbotMessageId + (msg.id === chatbotMessageId ? { ...msg, isLoading: false, @@ -306,7 +306,7 @@ const Chatbot: FC = (props) => { }, }, } - : msg + : msg) ) ); } diff --git a/frontend/src/components/Graph/GraphViewModal.tsx b/frontend/src/components/Graph/GraphViewModal.tsx index af5a7a90a..27610680d 100644 --- a/frontend/src/components/Graph/GraphViewModal.tsx +++ b/frontend/src/components/Graph/GraphViewModal.tsx @@ -63,10 +63,10 @@ const GraphViewModal: React.FunctionComponent = ({ graphType.includes('DocumentChunk') && graphType.includes('Entities') ? queryMap.DocChunkEntities : graphType.includes('DocumentChunk') - ? queryMap.DocChunks - : graphType.includes('Entities') - ? queryMap.Entities - : ''; + ? queryMap.DocChunks + : graphType.includes('Entities') + ? queryMap.Entities + : ''; // fit graph to original position const handleZoomToFit = () => { @@ -108,10 +108,10 @@ const GraphViewModal: React.FunctionComponent = ({ const nodeRelationshipData = viewPoint === graphLabels.showGraphView ? await graphQueryAPI( - userCredentials as UserCredentials, - graphQuery, - selectedRows?.map((f) => f.name) - ) + userCredentials as UserCredentials, + graphQuery, + selectedRows?.map((f) => f.name) + ) : await graphQueryAPI(userCredentials as UserCredentials, graphQuery, [inspectedName ?? '']); return nodeRelationshipData; } catch (error: any) { @@ -349,12 +349,14 @@ const GraphViewModal: React.FunctionComponent = ({ > {headerTitle} - {viewPoint !== graphLabels.chatInfoView && (
          - - - - {graphLabels.chunksInfo} -
          )} + {viewPoint !== graphLabels.chatInfoView && ( +
          + + + + {graphLabels.chunksInfo} +
          + )} {checkBoxView && ( { setDuplicateNodes((prev) => { return prev.map((d) => - d.e.elementId === nodeid + (d.e.elementId === nodeid ? { ...d, similar: d.similar.filter((n) => n.elementId != similarNodeId), } - : d + : d) ); }); }; diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx index fc5f39206..447b1f846 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx @@ -11,11 +11,11 @@ export default function SelectedJobList({ }) { const ongoingPostProcessingTasks = useMemo( () => - isGdsActive + (isGdsActive ? postProcessingTasks.includes('enable_communities') ? postProcessingTasks : postProcessingTasks.filter((s) => s != 'enable_communities') - : postProcessingTasks.filter((s) => s != 'enable_communities'), + : postProcessingTasks.filter((s) => s != 'enable_communities')), [isGdsActive, postProcessingTasks] ); return ( diff --git a/frontend/src/components/Popups/RetryConfirmation/Index.tsx b/frontend/src/components/Popups/RetryConfirmation/Index.tsx index 379be9598..4ae9b18eb 100644 --- a/frontend/src/components/Popups/RetryConfirmation/Index.tsx +++ b/frontend/src/components/Popups/RetryConfirmation/Index.tsx @@ -30,7 +30,8 @@ function RetryConfirmationDialog({ Reprocess Options - Clicking "Continue" will mark these files as "Ready to Reprocess." To proceed, click “Generate Graph” to start the reprocessing process. + Clicking "Continue" will mark these files as "Ready to Reprocess." To proceed, click “Generate Graph” to start + the reprocessing process. {alertStatus.showAlert && ( diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index 3488c2764..7cf35f506 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -295,7 +295,7 @@ export const graphLabels = { community: 'Communities', noNodesRels: 'No Nodes and No relationships', neighborView: 'neighborView', - chunksInfo:'We are processing 50 chunks at a time' + chunksInfo: 'We are processing 50 chunks at a time', }; export const RESULT_STEP_SIZE = 25; diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index 82217535d..7314c55e7 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -395,7 +395,7 @@ export const isFileCompleted = (waitingFile: CustomFile, item: SourceNode) => waitingFile && item.status === 'Completed'; export const calculateProcessedCount = (prev: number, batchSize: number) => - prev === batchSize ? batchSize - 1 : prev + 1; + (prev === batchSize ? batchSize - 1 : prev + 1); export const isProcessingFileValid = (item: SourceNode, userCredentials: UserCredentials) => { return item.status === 'Processing' && item.fileName != undefined && userCredentials && userCredentials.database; From f76d6848450bc6129394fd4a3ad99235649b8518 Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Tue, 26 Nov 2024 11:07:44 +0530 Subject: [PATCH 264/292] Env changes (#896) * env changes with state management * format and lint fixes * Update frontend_docs.adoc * Update backend_docs.adoc * state changes * error handling * button handling --- backend/score.py | 18 +- docs/backend/backend_docs.adoc | 23 ++ docs/frontend/frontend_docs.adoc | 74 ++++-- .../components/ChatBot/ChatOnlyComponent.tsx | 20 +- frontend/src/components/ChatBot/Chatbot.tsx | 2 +- frontend/src/components/Content.tsx | 207 ++++++++--------- .../src/components/Layout/DrawerDropzone.tsx | 102 ++++----- frontend/src/components/Layout/Header.tsx | 18 ++ frontend/src/components/Layout/PageLayout.tsx | 210 +++++++++++++++++- .../ConnectionModal/ConnectionModal.tsx | 10 +- frontend/src/context/UserCredentials.tsx | 19 +- frontend/src/services/ConnectAPI.ts | 14 +- frontend/src/services/GetFiles.ts | 4 +- frontend/src/types.ts | 9 + 14 files changed, 517 insertions(+), 213 deletions(-) diff --git a/backend/score.py b/backend/score.py index ac2468066..a64d22fca 100644 --- a/backend/score.py +++ b/backend/score.py @@ -557,6 +557,11 @@ def decode_password(pwd): decoded_password = sample_string_bytes.decode("utf-8") return decoded_password +def encode_password(pwd): + data_bytes = pwd.encode('ascii') + encoded_pwd_bytes = base64.b64encode(data_bytes) + return encoded_pwd_bytes + @app.get("/update_extract_status/{file_name}") async def update_extract_status(request:Request, file_name, url, userName, password, database): async def generate(): @@ -960,16 +965,25 @@ async def backend_connection_configuation(): print(f'login connection status of object: {graph}') if graph is not None: graph_connection = True - return create_api_response('Success',message=f"Backend connection successful",data=graph_connection) + isURI = os.getenv('NEO4J_URI') + isUsername= os.getenv('NEO4J_USERNAME') + isDatabase= os.getenv('NEO4J_DATABASE') + isPassword= os.getenv('NEO4J_PASSWORD') + encoded_password = encode_password(isPassword) + graphDb_data_Access = graphDBdataAccess(graph) + gds_status = graphDb_data_Access.check_gds_version() + write_access = graphDb_data_Access.check_account_access(database=isDatabase) + return create_api_response('Success',message=f"Backend connection successful",data={'graph_connection':graph_connection,'uri':isURI,'user_name':isUsername,'database':isDatabase,'password':encoded_password,'gds_status':gds_status,'write_access':write_access}) else: graph_connection = False return create_api_response('Success',message=f"Backend connection is not successful",data=graph_connection) except Exception as e: + graph_connection = False job_status = "Failed" message="Unable to connect backend DB" error_message = str(e) logging.exception(f'{error_message}') - return create_api_response(job_status, message=message, error=error_message) + return create_api_response(job_status, message=message, error=error_message + ' or fill from the login dialog', data=graph_connection) finally: gc.collect() diff --git a/docs/backend/backend_docs.adoc b/docs/backend/backend_docs.adoc index d313a3402..7f1fd11dc 100644 --- a/docs/backend/backend_docs.adoc +++ b/docs/backend/backend_docs.adoc @@ -979,3 +979,26 @@ The API responsible for a evaluating chatbot responses on the basis of different } } .... +=== Backend Database connection +---- +POST /backend_connection_configuation +---- + +The API responsible for create the connection obj from Neo4j DB based on environment variable and return the status for show/hide login dialog on UI + +**Response :** +[source,json,indent=0] +.... +{ + "status": "Success", + "data": true, + "message": "Backend connection successful" +} +.... + +.... +{ + "status": "Failed", + "error": "Could not connect to Neo4j database. Please ensure that the username and password are correct", + "message": "Unable to connect backend DB" +} diff --git a/docs/frontend/frontend_docs.adoc b/docs/frontend/frontend_docs.adoc index 9eaf1e4bc..34e71f254 100644 --- a/docs/frontend/frontend_docs.adoc +++ b/docs/frontend/frontend_docs.adoc @@ -18,53 +18,80 @@ This document provides a comprehensive guide for developers on how we build a Re . ├── Components | ├─ ChatBot - | | ├─ ChatBotInfoModal + | | ├─ ChatInfoModal | | ├─ ChatModeToggle | | ├─ ExpandedChatButtonContainer + | | ├─ ChatModesSwitch + | | ├─ ChatOnlyComponent + | | ├─ ChatInfo + | | ├─ CommonChatActions + | | ├─ CommunitiesInfo + | | ├─ EntitiesInfo + | | ├─ MetricsCheckbox + | | ├─ MetricsTab + | | ├─ MultiModeMetrics + | | ├─ SourcesInfo | ├─ Data Sources | | ├─ AWS | | ├─ GCS | | ├─ Local - | | ├─ WebSources - | | | ├─Web - | | | ├─Wikipedia - | | | ├─Youtube + | | ├─ Web + | | | ├─ WebButton | ├─ Graph + | | ├─ CheckboxSelection + | | ├─ GraphPropertiesPanel + | | ├─ GraphPropertiesTable | | ├─ GraphViewButton | | ├─ GraphViewModal | | ├─ LegendsChip + | | ├─ ResizePanel + | | ├─ ResultOverview | ├─ Layout - | | ├─ Content + | | ├─ AlertIcon | | ├─ DrawerChatbot | | ├─ DrawerDropzone | | ├─ Header | | ├─ PageLayout | | ├─ SideNav | ├─ Popups + | | ├─ ChunkPopUp | | ├─ ConnectionModal | | ├─ DeletePopup | | ├─ GraphEnhancementDialog | | ├─ LargeFilePopup + | | ├─ RetryConfirmation | | ├─ Settings | ├─ UI | | ├─ Alert | | ├─ ButtonWithTooltip | | ├─ CustomButton - | | ├─ CustomModal + | | ├─ CustomCheckBox + | | ├─ CustomMenu | | ├─ CustomProgressBar - | | ├─ CustomSourceInput - | | ├─ Dropdown + | | ├─ DatabaseIcon + | | ├─ DatabaseStatusIcon | | ├─ ErrorBoundary - | | ├─ FileTable - | | ├─ GenericSourceButton - | | ├─ GenericSourceModal + | | ├─ FallBackDialog | | ├─ HoverableLink | | ├─ IconButtonTooltip | | ├─ Legend - | | ├─ Menu - | | ├─ QuickStarter + | | ├─ ScienceMolecule + | | ├─ ShowAll + | | ├─ TipWrapper + | ├─ Websources + | | ├─ Web + | | ├─ Wikipedia + | | ├─ Youtube + | | ├─ CustomSourceInput + | | ├─ GenericSourceButton + | | ├─ GenericSourceModal + | ├─ Content + | ├─ Dropdown + | ├─ FileTable + | ├─ QuickStarter ├── HOC - | ├─ SettingModalHOC + | ├─ CustomModal + | ├─ withVisibility ├── Assets | ├─ images | | ├─ Application Images @@ -87,8 +114,14 @@ This document provides a comprehensive guide for developers on how we build a Re | ├─ constants | ├─ FileAPI | ├─ Loader - | ├─ Types + | ├─ Queue + | ├─ toats | ├─ utils + ├── App + ├── index + ├── main + ├── router + ├── types └── README.md == Application @@ -98,7 +131,10 @@ Added Node.js with version v21.1.0 and npm on the development machine. Install necessary dependencies by running yarn install, such as axios for making HTTP requests and others to interact with the graph. == 2. Connect to the Neo4j Aura instance: -Created a connection modal by adding details including protocol, URI, database name, username, and password. Added a submit button that triggers an API: ***/connect*** and accepts params like uri, password, username and database to establish a connection to the Neo4j Aura instance. Handled the authentication and error scenarios appropriately, by displaying relevant messages. To check whether the backend connection is up and working we hit the API: ***/health*** +Created a connection modal by adding details including protocol, URI, database name, username, and password. Added a submit button that triggers an API: ***/connect*** and accepts params like uri, password, username and database to establish a connection to the Neo4j Aura instance. Handled the authentication and error scenarios appropriately, by displaying relevant messages. To check whether the backend connection is up and working we hit the API: ***/health.*** The user can now access both AURA DS and AURA DB instances. + +* If GDS Connection is there icon is scientific molecule > Graph enhancement model > Post processing jobs > gives user the leverage to check and uncheck the communities checkbox. +* If AURA DB > icon is database icon > Graph enhancement model > Post processing jobs > communities checkbox is disabled. * Before Connection : @@ -241,6 +277,10 @@ User can delete all number/selected files from the table. image::images/DeleteFiles.jpg[DeleteFiles, 600] +* ***Chat Only Mode*** + +User can also use the chat only feature by navigating to the url https://dev-frontend-dcavk67s4a-uc.a.run.app/chat-only to ask questions related to documents which have been completely processed. User is required to pass the login credentials to connect to the database. + == 8. Interface Design: Designed a user-friendly interface that guides users through the process of connecting to Neo4j Aura, accessing file sources, uploading PDF files, and generating graphs. diff --git a/frontend/src/components/ChatBot/ChatOnlyComponent.tsx b/frontend/src/components/ChatBot/ChatOnlyComponent.tsx index 45accddcd..6d1e94b59 100644 --- a/frontend/src/components/ChatBot/ChatOnlyComponent.tsx +++ b/frontend/src/components/ChatBot/ChatOnlyComponent.tsx @@ -9,10 +9,11 @@ import Header from '../Layout/Header'; import { clearChatAPI } from '../../services/QnaAPI'; import { ChatProps, connectionState, Messages, UserCredentials } from '../../types'; import { getIsLoading } from '../../utils/Utils'; +import ThemeWrapper from '../../context/ThemeWrapper'; const ChatContent: React.FC = ({ chatMessages }) => { const { clearHistoryData, messages, setMessages, setClearHistoryData } = useMessageContext(); - const { setUserCredentials, setConnectionStatus, connectionStatus } = useCredentials(); + const { setUserCredentials, setConnectionStatus, connectionStatus, setShowDisconnectButton } = useCredentials(); const [showBackButton, setShowBackButton] = useReducer((state) => !state, false); const [openConnection, setOpenConnection] = useState({ openPopUp: false, @@ -58,6 +59,7 @@ const ChatContent: React.FC = ({ chatMessages }) => { */ const handleConnectionSuccess = () => { setConnectionStatus(true); + setShowDisconnectButton(true); setOpenConnection((prev) => ({ ...prev, openPopUp: false })); const urlParams = new URLSearchParams(window.location.search); urlParams.delete('openModal'); @@ -142,13 +144,15 @@ const ChatOnlyComponent: React.FC = () => { const location = useLocation(); const chatMessages = (location.state?.messages as Messages[]) || []; return ( - - - - - - - + + + + + + + + + ); }; export default ChatOnlyComponent; diff --git a/frontend/src/components/ChatBot/Chatbot.tsx b/frontend/src/components/ChatBot/Chatbot.tsx index 03d027d04..4cf1b12bb 100644 --- a/frontend/src/components/ChatBot/Chatbot.tsx +++ b/frontend/src/components/ChatBot/Chatbot.tsx @@ -411,7 +411,7 @@ const Chatbot: FC = (props) => {
          diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 552dc9506..48ef941ee 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -12,13 +12,12 @@ import { OptionType, UserCredentials, chunkdata, - connectionState, } from '../types'; import deleteAPI from '../services/DeleteFiles'; import { postProcessing } from '../services/PostProcessing'; import { triggerStatusUpdateAPI } from '../services/ServerSideStatusUpdateAPI'; import useServerSideEvent from '../hooks/useSse'; -import { useSearchParams } from 'react-router-dom'; +// import { useSearchParams } from 'react-router-dom'; import { batchSize, buttonCaptions, @@ -30,7 +29,6 @@ import { tooltips, } from '../utils/Constants'; import ButtonWithToolTip from './UI/ButtonWithToolTip'; -import connectAPI from '../services/ConnectAPI'; import DropdownComponent from './Dropdown'; import GraphViewModal from './Graph/GraphViewModal'; import { lazy } from 'react'; @@ -48,7 +46,6 @@ import PostProcessingToast from './Popups/GraphEnhancementDialog/PostProcessingC import { getChunkText } from '../services/getChunkText'; import ChunkPopUp from './Popups/ChunkPopUp'; -const ConnectionModal = lazy(() => import('./Popups/ConnectionModal/ConnectionModal')); const ConfirmationDialog = lazy(() => import('./Popups/LargeFilePopUp/ConfirmationDialog')); let afterFirstRender = false; @@ -60,29 +57,17 @@ const Content: React.FC = ({ setIsSchema, showEnhancementDialog, toggleEnhancementDialog, + setOpenConnection, + showDisconnectButton, + connectionStatus, }) => { const { breakpoints } = tokens; const isTablet = useMediaQuery(`(min-width:${breakpoints.xs}) and (max-width: ${breakpoints.lg})`); - const [init, setInit] = useState(false); - const [openConnection, setOpenConnection] = useState({ - openPopUp: false, - chunksExists: false, - vectorIndexMisMatch: false, - chunksExistsWithDifferentDimension: false, - }); + // const [init, setInit] = useState(false); const [openGraphView, setOpenGraphView] = useState(false); const [inspectedName, setInspectedName] = useState(''); const [documentName, setDocumentName] = useState(''); - const { - setUserCredentials, - userCredentials, - connectionStatus, - setConnectionStatus, - isGdsActive, - setGdsActive, - setIsReadOnlyUser, - isReadOnlyUser, - } = useCredentials(); + const { setUserCredentials, userCredentials, setConnectionStatus, isGdsActive, isReadOnlyUser } = useCredentials(); const [showConfirmationModal, setshowConfirmationModal] = useState(false); const [extractLoading, setextractLoading] = useState(false); const [retryFile, setRetryFile] = useState(''); @@ -121,7 +106,7 @@ const Content: React.FC = ({ ); const [showDeletePopUp, setshowDeletePopUp] = useState(false); const [deleteLoading, setdeleteLoading] = useState(false); - const [searchParams] = useSearchParams(); + // const [searchParams] = useSearchParams(); const { updateStatusForLargeFiles } = useServerSideEvent( (inMinutes, time, fileName) => { @@ -141,32 +126,32 @@ const Content: React.FC = ({ setCurrentPage((prev) => prev - 1); await getChunks(documentName, currentPage - 1); }; - useEffect(() => { - if (!init && !searchParams.has('connectURL')) { - let session = localStorage.getItem('neo4j.connection'); - if (session) { - let neo4jConnection = JSON.parse(session); - setUserCredentials({ - uri: neo4jConnection.uri, - userName: neo4jConnection.user, - password: atob(neo4jConnection.password), - database: neo4jConnection.database, - port: neo4jConnection.uri.split(':')[2], - }); - if (neo4jConnection.isgdsActive !== undefined) { - setGdsActive(neo4jConnection.isgdsActive); - } - if (neo4jConnection.isReadOnlyUser !== undefined) { - setIsReadOnlyUser(neo4jConnection.isReadOnlyUser); - } - } else { - setOpenConnection((prev) => ({ ...prev, openPopUp: true })); - } - setInit(true); - } else { - setOpenConnection((prev) => ({ ...prev, openPopUp: true })); - } - }, []); + // useEffect(() => { + // if (!init && !searchParams.has('connectURL')) { + // let session = localStorage.getItem('neo4j.connection'); + // if (session) { + // let neo4jConnection = JSON.parse(session); + // setUserCredentials({ + // uri: neo4jConnection.uri, + // userName: neo4jConnection.user, + // password: atob(neo4jConnection.password), + // database: neo4jConnection.database, + // port: neo4jConnection.uri.split(':')[2], + // }); + // if (neo4jConnection.isgdsActive !== undefined) { + // setGdsActive(neo4jConnection.isgdsActive); + // } + // if (neo4jConnection.isReadOnlyUser !== undefined) { + // setIsReadOnlyUser(neo4jConnection.isReadOnlyUser); + // } + // } else { + // setOpenConnection((prev) => ({ ...prev, openPopUp: true })); + // } + // setInit(true); + // } else { + // setOpenConnection((prev) => ({ ...prev, openPopUp: true })); + // } + // }, []); useEffect(() => { if (afterFirstRender) { localStorage.setItem('processedCount', JSON.stringify({ db: userCredentials?.uri, count: processedCount })); @@ -228,60 +213,60 @@ const Content: React.FC = ({ } }, [isSchema]); - useEffect(() => { - const connection = localStorage.getItem('neo4j.connection'); - if (connection != null) { - (async () => { - const parsedData = JSON.parse(connection); - const response = await connectAPI( - parsedData.uri, - parsedData.user, - atob(parsedData.password), - parsedData.database - ); - if (response?.data?.status === 'Success') { - localStorage.setItem( - 'neo4j.connection', - JSON.stringify({ - ...parsedData, - userDbVectorIndex: response.data.data.db_vector_dimension, - password: btoa(atob(parsedData.password)), - }) - ); - if (response.data.data.gds_status !== undefined) { - setGdsActive(response.data.data.gds_status); - } - if (response.data.data.write_access !== undefined) { - setIsReadOnlyUser(!response.data.data.write_access); - } - if ( - (response.data.data.application_dimension === response.data.data.db_vector_dimension || - response.data.data.db_vector_dimension == 0) && - !response.data.data.chunks_exists - ) { - setConnectionStatus(true); - setOpenConnection((prev) => ({ ...prev, openPopUp: false })); - } else { - setOpenConnection({ - openPopUp: true, - chunksExists: response.data.data.chunks_exists as boolean, - vectorIndexMisMatch: - response.data.data.db_vector_dimension > 0 && - response.data.data.db_vector_dimension != response.data.data.application_dimension, - chunksExistsWithDifferentDimension: - response.data.data.db_vector_dimension > 0 && - response.data.data.db_vector_dimension != response.data.data.application_dimension && - (response.data.data.chunks_exists ?? true), - }); - setConnectionStatus(false); - } - } else { - setOpenConnection((prev) => ({ ...prev, openPopUp: true })); - setConnectionStatus(false); - } - })(); - } - }, []); + // useEffect(() => { + // const connection = localStorage.getItem('neo4j.connection'); + // if (connection != null) { + // (async () => { + // const parsedData = JSON.parse(connection); + // const response = await connectAPI( + // parsedData.uri, + // parsedData.user, + // atob(parsedData.password), + // parsedData.database + // ); + // if (response?.data?.status === 'Success') { + // localStorage.setItem( + // 'neo4j.connection', + // JSON.stringify({ + // ...parsedData, + // userDbVectorIndex: response.data.data.db_vector_dimension, + // password: btoa(atob(parsedData.password)), + // }) + // ); + // if (response.data.data.gds_status !== undefined) { + // setGdsActive(response.data.data.gds_status); + // } + // if (response.data.data.write_access !== undefined) { + // setIsReadOnlyUser(!response.data.data.write_access); + // } + // if ( + // (response.data.data.application_dimension === response.data.data.db_vector_dimension || + // response.data.data.db_vector_dimension == 0) && + // !response.data.data.chunks_exists + // ) { + // setConnectionStatus(true); + // setOpenConnection((prev) => ({ ...prev, openPopUp: false })); + // } else { + // setOpenConnection({ + // openPopUp: true, + // chunksExists: response.data.data.chunks_exists as boolean, + // vectorIndexMisMatch: + // response.data.data.db_vector_dimension > 0 && + // response.data.data.db_vector_dimension != response.data.data.application_dimension, + // chunksExistsWithDifferentDimension: + // response.data.data.db_vector_dimension > 0 && + // response.data.data.db_vector_dimension != response.data.data.application_dimension && + // (response.data.data.chunks_exists ?? true), + // }); + // setConnectionStatus(false); + // } + // } else { + // setOpenConnection((prev) => ({ ...prev, openPopUp: true })); + // setConnectionStatus(false); + // } + // })(); + // } + // }, []); const handleDropdownChange = (selectedOption: OptionType | null | void) => { if (selectedOption?.value) { @@ -880,16 +865,6 @@ const Content: React.FC = ({ )}
          - }> - -
          Neo4j connection {isReadOnlyUser ? '(Read only Mode)' : ''} @@ -944,9 +919,11 @@ const Content: React.FC = ({ {buttonCaptions.connectToNeo4j} ) : ( - + showDisconnectButton && ( + + ) )}
          diff --git a/frontend/src/components/Layout/DrawerDropzone.tsx b/frontend/src/components/Layout/DrawerDropzone.tsx index 6560bc2ad..f84910d3d 100644 --- a/frontend/src/components/Layout/DrawerDropzone.tsx +++ b/frontend/src/components/Layout/DrawerDropzone.tsx @@ -1,7 +1,6 @@ import { Drawer, Flex, StatusIndicator, Typography } from '@neo4j-ndl/react'; import DropZone from '../DataSources/Local/DropZone'; -import React, { useState, useEffect, useMemo, Suspense, lazy } from 'react'; -import { healthStatus } from '../../services/HealthStatus'; +import React, { useMemo, Suspense, lazy } from 'react'; import S3Component from '../DataSources/AWS/S3Bucket'; import { DrawerProps } from '../../types'; import GCSButton from '../DataSources/GCS/GCSButton'; @@ -24,21 +23,8 @@ const DrawerDropzone: React.FC = ({ showGCSModal, showGenericModal, }) => { - const [isBackendConnected, setIsBackendConnected] = useState(false); const { closeAlert, alertState } = useAlertContext(); - const { isReadOnlyUser } = useCredentials(); - - useEffect(() => { - async function getHealthStatus() { - try { - const response = await healthStatus(); - setIsBackendConnected(response.data.healthy); - } catch (error) { - setIsBackendConnected(false); - } - } - getHealthStatus(); - }, []); + const { isReadOnlyUser, isBackendConnected } = useCredentials(); const isYoutubeOnlyCheck = useMemo( () => APP_SOURCES?.includes('youtube') && !APP_SOURCES.includes('wiki') && !APP_SOURCES.includes('web'), @@ -70,9 +56,8 @@ const DrawerDropzone: React.FC = ({
          {process.env.VITE_ENV != 'PROD' && ( @@ -92,31 +77,29 @@ const DrawerDropzone: React.FC = ({
          )} {(APP_SOURCES != undefined && APP_SOURCES.includes('s3')) || - (APP_SOURCES != undefined && APP_SOURCES.includes('gcs')) ? ( + (APP_SOURCES != undefined && APP_SOURCES.includes('gcs')) ? ( <> {(APP_SOURCES.includes('youtube') || APP_SOURCES.includes('wiki') || APP_SOURCES.includes('web')) && ( -
          - - -
          - )} +
          + + +
          + )} {APP_SOURCES.includes('s3') && (
          }> @@ -126,9 +109,8 @@ const DrawerDropzone: React.FC = ({ )} {APP_SOURCES.includes('gcs') && (
          }> @@ -157,27 +139,26 @@ const DrawerDropzone: React.FC = ({ {((APP_SOURCES != undefined && APP_SOURCES.includes('youtube')) || (APP_SOURCES != undefined && APP_SOURCES.includes('wiki')) || (APP_SOURCES != undefined && APP_SOURCES.includes('web'))) && ( -
          - - -
          - )} +
          + + +
          + )} {(APP_SOURCES != undefined && APP_SOURCES.includes('s3')) || - (APP_SOURCES != undefined && APP_SOURCES.includes('gcs')) ? ( + (APP_SOURCES != undefined && APP_SOURCES.includes('gcs')) ? ( <> {APP_SOURCES != undefined && APP_SOURCES.includes('s3') && (
          }> @@ -187,9 +168,8 @@ const DrawerDropzone: React.FC = ({ )} {APP_SOURCES != undefined && APP_SOURCES.includes('gcs') && (
          = ({ chatOnly, deleteOnClick, setOpenConnecti )} + + {colorMode === 'dark' ? ( + + + + ) : ( + + + + )} +
          { diff --git a/frontend/src/components/Layout/PageLayout.tsx b/frontend/src/components/Layout/PageLayout.tsx index 31f3ba8cb..5cfe7bd12 100644 --- a/frontend/src/components/Layout/PageLayout.tsx +++ b/frontend/src/components/Layout/PageLayout.tsx @@ -1,22 +1,33 @@ -import { useReducer, useState } from 'react'; +import { lazy, Suspense, useEffect, useReducer, useState } from 'react'; import SideNav from './SideNav'; import DrawerDropzone from './DrawerDropzone'; import DrawerChatbot from './DrawerChatbot'; import Content from '../Content'; import { clearChatAPI } from '../../services/QnaAPI'; import { useCredentials } from '../../context/UserCredentials'; -import { UserCredentials } from '../../types'; +import { connectionState, UserCredentials } from '../../types'; import { useMessageContext } from '../../context/UserMessages'; import { useMediaQuery } from '@mui/material'; import { useFileContext } from '../../context/UsersFiles'; import SchemaFromTextDialog from '../Popups/Settings/SchemaFromText'; import useSpeechSynthesis from '../../hooks/useSpeech'; +import FallBackDialog from '../UI/FallBackDialog'; +import { envConnectionAPI } from '../../services/ConnectAPI'; +import { healthStatus } from '../../services/HealthStatus'; + +const ConnectionModal = lazy(() => import('../Popups/ConnectionModal/ConnectionModal')); interface PageLayoutProp { isChatOnly?: boolean; } const PageLayout: React.FC = () => { + const [openConnection, setOpenConnection] = useState({ + openPopUp: false, + chunksExists: false, + vectorIndexMisMatch: false, + chunksExistsWithDifferentDimension: false, + }); const largedesktops = useMediaQuery(`(min-width:1440px )`); const { userCredentials, connectionStatus } = useCredentials(); const [isLeftExpanded, setIsLeftExpanded] = useState(Boolean(largedesktops)); @@ -27,6 +38,7 @@ const PageLayout: React.FC = () => { const [shows3Modal, toggleS3Modal] = useReducer((s) => !s, false); const [showGCSModal, toggleGCSModal] = useReducer((s) => !s, false); const [showGenericModal, toggleGenericModal] = useReducer((s) => !s, false); + const toggleLeftDrawer = () => { if (largedesktops) { setIsLeftExpanded(!isLeftExpanded); @@ -44,7 +56,188 @@ const PageLayout: React.FC = () => { const { messages, setClearHistoryData, clearHistoryData, setMessages } = useMessageContext(); const { isSchema, setIsSchema, setShowTextFromSchemaDialog, showTextFromSchemaDialog } = useFileContext(); + const { + setConnectionStatus, + setGdsActive, + setIsReadOnlyUser, + setIsBackendConnected, + setUserCredentials, + setErrorMessage, + setShowDisconnectButton, + showDisconnectButton, + } = useCredentials(); const { cancel } = useSpeechSynthesis(); + + + useEffect(() => { + async function initializeConnection() { + const session = localStorage.getItem('neo4j.connection'); + const environment = process.env.VITE_ENV; + const isDev = environment === 'DEV'; + // Fetch backend health status + try { + const response = await healthStatus(); + setIsBackendConnected(response.data.healthy); + } catch (error) { + setIsBackendConnected(false); + } + // To set the disconnect button state + const handleDisconnectButtonState = (isModalOpen: boolean) => { + setShowDisconnectButton(isModalOpen); + localStorage.setItem('disconnectButtonState', isModalOpen ? 'true' : 'false'); + } + // To parse and set user credentials from session + const setUserCredentialsFromSession = (neo4jConnection: string) => { + if (!neo4jConnection) { + console.error('Invalid session data:', neo4jConnection); + return; + } + try { + const parsedConnection = JSON.parse(neo4jConnection); + if ( + parsedConnection.uri && + parsedConnection.user && + parsedConnection.password && + parsedConnection.database && + typeof parsedConnection.uri === 'string' && + typeof parsedConnection.user === 'string' && + typeof parsedConnection.password === 'string' && + typeof parsedConnection.database === 'string' + ) { + setUserCredentials({ + uri: parsedConnection.uri, + userName: parsedConnection.user, + password: atob(parsedConnection.password), + database: parsedConnection.database, + }); + setGdsActive(parsedConnection.isGDS); + //setIsReadOnlyUser(parsedConnection.isReadOnlyUser || false); + } else { + console.error('Invalid parsed session data:', parsedConnection); + } + } catch (error) { + console.error('Failed to parse session data:', error); + } + } + // To update credentials if environment values differ + const updateSessionIfNeeded = (envCredentials: UserCredentials, storedSession: string) => { + try { + const storedCredentials = JSON.parse(storedSession); + const isDiffCreds = + envCredentials.uri !== storedCredentials.uri || + envCredentials.userName !== storedCredentials.user || + btoa(envCredentials.password) !== storedCredentials.password || + envCredentials.database !== storedCredentials.database; + if (isDiffCreds) { + setUserCredentials(envCredentials); + localStorage.setItem( + 'neo4j.connection', + JSON.stringify({ + uri: envCredentials.uri, + user: envCredentials.userName, + password: btoa(envCredentials.password), + database: envCredentials.database, + userDbVectorIndex: 384, + // isReadOnlyUser: envCredentials.isReadonlyUser, + isGDS: envCredentials.isGds, + }) + ); + return true; + } + return false; + } catch (error) { + console.error('Failed to update session:', error); + return false; + } + } + try { + // Handle case where session exists + if (session) { + if (isDev) { + let backendApiResponse; + try { + backendApiResponse = await envConnectionAPI(); + const connectionData = backendApiResponse.data; + const envCredentials = { + uri: connectionData.data.uri, + password: atob(connectionData.data.password), + userName: connectionData.data.user_name, + database: connectionData.data.database, + // isReadonlyUser: connectionData.data.write_access, + isGds: connectionData.data.gds_status, + }; + const updated = updateSessionIfNeeded(envCredentials, session); + if (!updated) { + setUserCredentialsFromSession(session); // Using stored session if no update is needed + } + setConnectionStatus(!!connectionData.data.graph_connection); + setIsBackendConnected(true); + handleDisconnectButtonState(false); + } catch (error) { + console.error('Error in DEV session handling:', error); + handleDisconnectButtonState(true); + setOpenConnection((prev) => ({ ...prev, openPopUp: true })); + setErrorMessage(backendApiResponse?.data.error); + } + } else { + // For PROD, picking the session values + setUserCredentialsFromSession(session); + setConnectionStatus(true); + setIsBackendConnected(true); + handleDisconnectButtonState(true); + } + return; + } + // Handle case where no session exists + if (isDev) { + let envAPiResponse; + try { + envAPiResponse = await envConnectionAPI(); + const connectionData = envAPiResponse.data.data; + const credentials = { + uri: connectionData.uri, + password: atob(connectionData.password), + userName: connectionData.user_name, + database: connectionData.database, + // isReadonlyUser: connectionData.write_access, + isGds: connectionData.gds_status, + }; + setUserCredentials(credentials); + localStorage.setItem( + 'neo4j.connection', + JSON.stringify({ + uri: credentials.uri, + user: credentials.userName, + password: btoa(credentials.password), + database: credentials.database, + userDbVectorIndex: 384, + // isReadOnlyUser: credentials.isReadonlyUser, + isGDS: credentials.isGds, + }) + ); + setConnectionStatus(!!connectionData.graph_connection); + setIsBackendConnected(true); + handleDisconnectButtonState(false); + } catch (error) { + console.error('Error in DEV no-session handling:', error); + handleDisconnectButtonState(true); + setOpenConnection((prev) => ({ ...prev, openPopUp: true })); + setErrorMessage(envAPiResponse?.data.error); + } + } else { + // For PROD: Open modal to manually connect + handleDisconnectButtonState(true); + setOpenConnection((prev) => ({ ...prev, openPopUp: true })); + setIsBackendConnected(false); + } + } catch (error) { + console.error('Error in initializeConnection:', error); + setIsBackendConnected(false); + } + } + initializeConnection(); + }, []); + const deleteOnClick = async () => { try { setClearHistoryData(true); @@ -79,6 +272,16 @@ const PageLayout: React.FC = () => { return (
          + }> + + = () => { setIsSchema={setIsSchema} showEnhancementDialog={showEnhancementDialog} toggleEnhancementDialog={toggleEnhancementDialog} + setOpenConnection={setOpenConnection} + showDisconnectButton={showDisconnectButton} + connectionStatus={connectionStatus} /> {showDrawerChatbot && ( (initialusername ?? 'neo4j'); const [password, setPassword] = useState(''); const [connectionMessage, setMessage] = useState({ type: 'unknown', content: '' }); - const { setUserCredentials, userCredentials, setGdsActive, setIsReadOnlyUser } = useCredentials(); + const { setUserCredentials, userCredentials, setGdsActive, setIsReadOnlyUser, errorMessage } = useCredentials(); const [isLoading, setIsLoading] = useState(false); const [searchParams, setSearchParams] = useSearchParams(); const [userDbVectorIndex, setUserDbVectorIndex] = useState(initialuserdbvectorindex ?? undefined); @@ -123,6 +123,12 @@ export default function ConnectionModal({ } }, [isVectorIndexMatch, chunksExistsWithDifferentEmbedding, chunksExistsWithoutEmbedding, userCredentials]); + useEffect(() => { + if (errorMessage) { + setMessage({ type: 'danger', content: errorMessage }); + } + }, [errorMessage]); + const parseAndSetURI = (uri: string, urlparams = false) => { const uriParts: string[] = uri.split('://'); let uriHost: string[] | string; diff --git a/frontend/src/context/UserCredentials.tsx b/frontend/src/context/UserCredentials.tsx index cd3db2d62..29eee0c14 100644 --- a/frontend/src/context/UserCredentials.tsx +++ b/frontend/src/context/UserCredentials.tsx @@ -1,4 +1,4 @@ -import { createContext, useState, useContext, FunctionComponent, ReactNode, useReducer } from 'react'; +import { createContext, useState, useContext, FunctionComponent, ReactNode } from 'react'; import { ContextProps, UserCredentials } from '../types'; type Props = { @@ -14,6 +14,12 @@ export const UserConnection = createContext({ setConnectionStatus: () => null, isReadOnlyUser: false, setIsReadOnlyUser: () => null, + isBackendConnected: false, + setIsBackendConnected: () => null, + errorMessage: '', + setErrorMessage: () => null, + showDisconnectButton: false, + setShowDisconnectButton: () => null, }); export const useCredentials = () => { const userCredentials = useContext(UserConnection); @@ -23,7 +29,10 @@ const UserCredentialsWrapper: FunctionComponent = (props) => { const [userCredentials, setUserCredentials] = useState(null); const [isGdsActive, setGdsActive] = useState(false); const [isReadOnlyUser, setIsReadOnlyUser] = useState(false); - const [connectionStatus, setConnectionStatus] = useReducer((state) => !state, false); + const [connectionStatus, setConnectionStatus] = useState(false); + const [isBackendConnected, setIsBackendConnected] = useState(false); + const [errorMessage, setErrorMessage] = useState(''); + const [showDisconnectButton, setShowDisconnectButton] = useState(false); const value = { userCredentials, setUserCredentials, @@ -33,6 +42,12 @@ const UserCredentialsWrapper: FunctionComponent = (props) => { setConnectionStatus, isReadOnlyUser, setIsReadOnlyUser, + isBackendConnected, + setIsBackendConnected, + errorMessage, + setErrorMessage, + showDisconnectButton, + setShowDisconnectButton, }; return {props.children}; diff --git a/frontend/src/services/ConnectAPI.ts b/frontend/src/services/ConnectAPI.ts index 026c41c44..c802a5946 100644 --- a/frontend/src/services/ConnectAPI.ts +++ b/frontend/src/services/ConnectAPI.ts @@ -18,4 +18,16 @@ const connectAPI = async (connectionURI: string, username: string, password: str throw error; } }; -export default connectAPI; + +const envConnectionAPI = async () => { + try { + const conectionUrl = `/backend_connection_configuation`; + const response = await api.post(conectionUrl); + return response; + } catch (error) { + console.log('API Connection error', error); + throw error; + } +}; + +export { connectAPI, envConnectionAPI }; diff --git a/frontend/src/services/GetFiles.ts b/frontend/src/services/GetFiles.ts index 056a9cc05..4193a1d6b 100644 --- a/frontend/src/services/GetFiles.ts +++ b/frontend/src/services/GetFiles.ts @@ -3,9 +3,9 @@ import api from '../API/Index'; export const getSourceNodes = async (userCredentials: UserCredentials) => { try { - const encodedstr = btoa(userCredentials.password); + const encodedstr = btoa(userCredentials?.password); const response = await api.get( - `/sources_list?uri=${userCredentials.uri}&database=${userCredentials.database}&userName=${userCredentials.userName}&password=${encodedstr}` + `/sources_list?uri=${userCredentials?.uri}&database=${userCredentials?.database}&userName=${userCredentials?.userName}&password=${encodedstr}` ); return response; } catch (error) { diff --git a/frontend/src/types.ts b/frontend/src/types.ts index fcb170604..41b652683 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -152,6 +152,9 @@ export interface ContentProps { setIsSchema: Dispatch>; showEnhancementDialog: boolean; toggleEnhancementDialog: () => void; + setOpenConnection: Dispatch>; + showDisconnectButton: boolean; + connectionStatus: boolean; } export interface FileTableProps { @@ -748,6 +751,12 @@ export interface ContextProps { setIsReadOnlyUser: Dispatch>; connectionStatus: boolean; setConnectionStatus: Dispatch>; + isBackendConnected: boolean; + setIsBackendConnected: Dispatch>; + errorMessage: string; + setErrorMessage: Dispatch>; + showDisconnectButton: boolean; + setShowDisconnectButton: Dispatch>; } export interface MessageContextType { messages: Messages[] | []; From 63325f96fe36e4b45c392627238c314ce491be9d Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Tue, 26 Nov 2024 16:12:07 +0530 Subject: [PATCH 265/292] Update Content.tsx --- frontend/src/components/Content.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 48ef941ee..47614e042 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -165,8 +165,8 @@ const Content: React.FC = ({ try { const response = await postProcessing(userCredentials as UserCredentials, postProcessingTasks); if (response.data.status === 'Success') { - const communityfiles = response.data.data; - communityfiles.forEach((c: any) => { + const communityfiles = response.data?.data; + communityfiles?.forEach((c: any) => { setFilesData((prev) => { return prev.map((f) => { if (f.name === c.filename) { From 1992de7bfb3a1c40f4dc83794c88127b8622062d Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Tue, 26 Nov 2024 16:13:09 +0530 Subject: [PATCH 266/292] Update Content.tsx --- frontend/src/components/Content.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 47614e042..9b39e7b99 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -450,8 +450,8 @@ const Content: React.FC = ({ try { const response = await postProcessing(userCredentials as UserCredentials, postProcessingTasks); if (response.data.status === 'Success') { - const communityfiles = response.data.data; - communityfiles.forEach((c: any) => { + const communityfiles = response.data?.data; + communityfiles?.forEach((c: any) => { setFilesData((prev) => { return prev.map((f) => { if (f.name === c.filename) { From 3e348743462a1e242d59e837642d849b02f0a9b1 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Wed, 27 Nov 2024 08:56:19 +0000 Subject: [PATCH 267/292] build fix --- frontend/src/components/Layout/PageLayout.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/components/Layout/PageLayout.tsx b/frontend/src/components/Layout/PageLayout.tsx index 5cfe7bd12..7f3b75185 100644 --- a/frontend/src/components/Layout/PageLayout.tsx +++ b/frontend/src/components/Layout/PageLayout.tsx @@ -59,7 +59,6 @@ const PageLayout: React.FC = () => { const { setConnectionStatus, setGdsActive, - setIsReadOnlyUser, setIsBackendConnected, setUserCredentials, setErrorMessage, From 22a57c562a645767da4563a1fdaedd5e20fb9212 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Wed, 27 Nov 2024 11:33:53 +0000 Subject: [PATCH 268/292] communitifiles array check --- frontend/src/components/Content.tsx | 170 +++++------------- .../src/components/Layout/DrawerDropzone.tsx | 84 +++++---- frontend/src/components/Layout/Header.tsx | 2 +- frontend/src/components/Layout/PageLayout.tsx | 67 ++++--- 4 files changed, 120 insertions(+), 203 deletions(-) diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 9b39e7b99..0b27db6b6 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -4,20 +4,11 @@ import { Button, Typography, Flex, StatusIndicator, useMediaQuery } from '@neo4j import { useCredentials } from '../context/UserCredentials'; import { useFileContext } from '../context/UsersFiles'; import { extractAPI } from '../utils/FileAPI'; -import { - BannerAlertProps, - ChildRef, - ContentProps, - CustomFile, - OptionType, - UserCredentials, - chunkdata, -} from '../types'; +import { BannerAlertProps, ChildRef, ContentProps, CustomFile, OptionType, UserCredentials, chunkdata } from '../types'; import deleteAPI from '../services/DeleteFiles'; import { postProcessing } from '../services/PostProcessing'; import { triggerStatusUpdateAPI } from '../services/ServerSideStatusUpdateAPI'; import useServerSideEvent from '../hooks/useSse'; -// import { useSearchParams } from 'react-router-dom'; import { batchSize, buttonCaptions, @@ -106,7 +97,6 @@ const Content: React.FC = ({ ); const [showDeletePopUp, setshowDeletePopUp] = useState(false); const [deleteLoading, setdeleteLoading] = useState(false); - // const [searchParams] = useSearchParams(); const { updateStatusForLargeFiles } = useServerSideEvent( (inMinutes, time, fileName) => { @@ -126,32 +116,7 @@ const Content: React.FC = ({ setCurrentPage((prev) => prev - 1); await getChunks(documentName, currentPage - 1); }; - // useEffect(() => { - // if (!init && !searchParams.has('connectURL')) { - // let session = localStorage.getItem('neo4j.connection'); - // if (session) { - // let neo4jConnection = JSON.parse(session); - // setUserCredentials({ - // uri: neo4jConnection.uri, - // userName: neo4jConnection.user, - // password: atob(neo4jConnection.password), - // database: neo4jConnection.database, - // port: neo4jConnection.uri.split(':')[2], - // }); - // if (neo4jConnection.isgdsActive !== undefined) { - // setGdsActive(neo4jConnection.isgdsActive); - // } - // if (neo4jConnection.isReadOnlyUser !== undefined) { - // setIsReadOnlyUser(neo4jConnection.isReadOnlyUser); - // } - // } else { - // setOpenConnection((prev) => ({ ...prev, openPopUp: true })); - // } - // setInit(true); - // } else { - // setOpenConnection((prev) => ({ ...prev, openPopUp: true })); - // } - // }, []); + useEffect(() => { if (afterFirstRender) { localStorage.setItem('processedCount', JSON.stringify({ db: userCredentials?.uri, count: processedCount })); @@ -166,26 +131,28 @@ const Content: React.FC = ({ const response = await postProcessing(userCredentials as UserCredentials, postProcessingTasks); if (response.data.status === 'Success') { const communityfiles = response.data?.data; - communityfiles?.forEach((c: any) => { - setFilesData((prev) => { - return prev.map((f) => { - if (f.name === c.filename) { - return { - ...f, - chunkNodeCount: c.chunkNodeCount ?? 0, - entityNodeCount: c.entityNodeCount ?? 0, - communityNodeCount: c.communityNodeCount ?? 0, - chunkRelCount: c.chunkRelCount ?? 0, - entityEntityRelCount: c.entityEntityRelCount ?? 0, - communityRelCount: c.communityRelCount ?? 0, - nodesCount: c.nodeCount, - relationshipsCount: c.relationshipCount, - }; - } - return f; + if (Array.isArray(communityfiles) && communityfiles.length) { + communityfiles?.forEach((c: any) => { + setFilesData((prev) => { + return prev.map((f) => { + if (f.name === c.filename) { + return { + ...f, + chunkNodeCount: c.chunkNodeCount ?? 0, + entityNodeCount: c.entityNodeCount ?? 0, + communityNodeCount: c.communityNodeCount ?? 0, + chunkRelCount: c.chunkRelCount ?? 0, + entityEntityRelCount: c.entityEntityRelCount ?? 0, + communityRelCount: c.communityRelCount ?? 0, + nodesCount: c.nodeCount, + relationshipsCount: c.relationshipCount, + }; + } + return f; + }); }); }); - }); + } showSuccessToast('All Q&A functionality is available now.'); } else { throw new Error(response.data.error); @@ -213,61 +180,6 @@ const Content: React.FC = ({ } }, [isSchema]); - // useEffect(() => { - // const connection = localStorage.getItem('neo4j.connection'); - // if (connection != null) { - // (async () => { - // const parsedData = JSON.parse(connection); - // const response = await connectAPI( - // parsedData.uri, - // parsedData.user, - // atob(parsedData.password), - // parsedData.database - // ); - // if (response?.data?.status === 'Success') { - // localStorage.setItem( - // 'neo4j.connection', - // JSON.stringify({ - // ...parsedData, - // userDbVectorIndex: response.data.data.db_vector_dimension, - // password: btoa(atob(parsedData.password)), - // }) - // ); - // if (response.data.data.gds_status !== undefined) { - // setGdsActive(response.data.data.gds_status); - // } - // if (response.data.data.write_access !== undefined) { - // setIsReadOnlyUser(!response.data.data.write_access); - // } - // if ( - // (response.data.data.application_dimension === response.data.data.db_vector_dimension || - // response.data.data.db_vector_dimension == 0) && - // !response.data.data.chunks_exists - // ) { - // setConnectionStatus(true); - // setOpenConnection((prev) => ({ ...prev, openPopUp: false })); - // } else { - // setOpenConnection({ - // openPopUp: true, - // chunksExists: response.data.data.chunks_exists as boolean, - // vectorIndexMisMatch: - // response.data.data.db_vector_dimension > 0 && - // response.data.data.db_vector_dimension != response.data.data.application_dimension, - // chunksExistsWithDifferentDimension: - // response.data.data.db_vector_dimension > 0 && - // response.data.data.db_vector_dimension != response.data.data.application_dimension && - // (response.data.data.chunks_exists ?? true), - // }); - // setConnectionStatus(false); - // } - // } else { - // setOpenConnection((prev) => ({ ...prev, openPopUp: true })); - // setConnectionStatus(false); - // } - // })(); - // } - // }, []); - const handleDropdownChange = (selectedOption: OptionType | null | void) => { if (selectedOption?.value) { setModel(selectedOption?.value); @@ -451,26 +363,28 @@ const Content: React.FC = ({ const response = await postProcessing(userCredentials as UserCredentials, postProcessingTasks); if (response.data.status === 'Success') { const communityfiles = response.data?.data; - communityfiles?.forEach((c: any) => { - setFilesData((prev) => { - return prev.map((f) => { - if (f.name === c.filename) { - return { - ...f, - chunkNodeCount: c.chunkNodeCount ?? 0, - entityNodeCount: c.entityNodeCount ?? 0, - communityNodeCount: c.communityNodeCount ?? 0, - chunkRelCount: c.chunkRelCount ?? 0, - entityEntityRelCount: c.entityEntityRelCount ?? 0, - communityRelCount: c.communityRelCount ?? 0, - nodesCount: c.nodeCount, - relationshipsCount: c.relationshipCount, - }; - } - return f; + if (Array.isArray(communityfiles) && communityfiles.length) { + communityfiles?.forEach((c: any) => { + setFilesData((prev) => { + return prev.map((f) => { + if (f.name === c.filename) { + return { + ...f, + chunkNodeCount: c.chunkNodeCount ?? 0, + entityNodeCount: c.entityNodeCount ?? 0, + communityNodeCount: c.communityNodeCount ?? 0, + chunkRelCount: c.chunkRelCount ?? 0, + entityEntityRelCount: c.entityEntityRelCount ?? 0, + communityRelCount: c.communityRelCount ?? 0, + nodesCount: c.nodeCount, + relationshipsCount: c.relationshipCount, + }; + } + return f; + }); }); }); - }); + } showSuccessToast('All Q&A functionality is available now.'); } else { throw new Error(response.data.error); diff --git a/frontend/src/components/Layout/DrawerDropzone.tsx b/frontend/src/components/Layout/DrawerDropzone.tsx index f84910d3d..4b9e89dc4 100644 --- a/frontend/src/components/Layout/DrawerDropzone.tsx +++ b/frontend/src/components/Layout/DrawerDropzone.tsx @@ -56,8 +56,9 @@ const DrawerDropzone: React.FC = ({
          {process.env.VITE_ENV != 'PROD' && ( @@ -77,29 +78,31 @@ const DrawerDropzone: React.FC = ({
          )} {(APP_SOURCES != undefined && APP_SOURCES.includes('s3')) || - (APP_SOURCES != undefined && APP_SOURCES.includes('gcs')) ? ( + (APP_SOURCES != undefined && APP_SOURCES.includes('gcs')) ? ( <> {(APP_SOURCES.includes('youtube') || APP_SOURCES.includes('wiki') || APP_SOURCES.includes('web')) && ( -
          - - -
          - )} +
          + + +
          + )} {APP_SOURCES.includes('s3') && (
          }> @@ -109,8 +112,9 @@ const DrawerDropzone: React.FC = ({ )} {APP_SOURCES.includes('gcs') && (
          }> @@ -139,26 +143,27 @@ const DrawerDropzone: React.FC = ({ {((APP_SOURCES != undefined && APP_SOURCES.includes('youtube')) || (APP_SOURCES != undefined && APP_SOURCES.includes('wiki')) || (APP_SOURCES != undefined && APP_SOURCES.includes('web'))) && ( -
          - - -
          - )} +
          + + +
          + )} {(APP_SOURCES != undefined && APP_SOURCES.includes('s3')) || - (APP_SOURCES != undefined && APP_SOURCES.includes('gcs')) ? ( + (APP_SOURCES != undefined && APP_SOURCES.includes('gcs')) ? ( <> {APP_SOURCES != undefined && APP_SOURCES.includes('s3') && (
          }> @@ -168,8 +173,9 @@ const DrawerDropzone: React.FC = ({ )} {APP_SOURCES != undefined && APP_SOURCES.includes('gcs') && (
          = ({ chatOnly, deleteOnClick, setOpenConnecti const userName = neo4jConnection.user; const { password } = neo4jConnection; const { database } = neo4jConnection; - const port = uri.split(':')[2]; + const [,port]= uri.split(':'); const encodedPassword = btoa(password); const chatUrl = `/chat-only?uri=${encodeURIComponent( uri diff --git a/frontend/src/components/Layout/PageLayout.tsx b/frontend/src/components/Layout/PageLayout.tsx index 7f3b75185..764f32e78 100644 --- a/frontend/src/components/Layout/PageLayout.tsx +++ b/frontend/src/components/Layout/PageLayout.tsx @@ -67,7 +67,6 @@ const PageLayout: React.FC = () => { } = useCredentials(); const { cancel } = useSpeechSynthesis(); - useEffect(() => { async function initializeConnection() { const session = localStorage.getItem('neo4j.connection'); @@ -84,7 +83,7 @@ const PageLayout: React.FC = () => { const handleDisconnectButtonState = (isModalOpen: boolean) => { setShowDisconnectButton(isModalOpen); localStorage.setItem('disconnectButtonState', isModalOpen ? 'true' : 'false'); - } + }; // To parse and set user credentials from session const setUserCredentialsFromSession = (neo4jConnection: string) => { if (!neo4jConnection) { @@ -110,14 +109,14 @@ const PageLayout: React.FC = () => { database: parsedConnection.database, }); setGdsActive(parsedConnection.isGDS); - //setIsReadOnlyUser(parsedConnection.isReadOnlyUser || false); + // setIsReadOnlyUser(parsedConnection.isReadOnlyUser || false); } else { console.error('Invalid parsed session data:', parsedConnection); } } catch (error) { console.error('Failed to parse session data:', error); } - } + }; // To update credentials if environment values differ const updateSessionIfNeeded = (envCredentials: UserCredentials, storedSession: string) => { try { @@ -148,43 +147,41 @@ const PageLayout: React.FC = () => { console.error('Failed to update session:', error); return false; } - } + }; try { // Handle case where session exists - if (session) { - if (isDev) { - let backendApiResponse; - try { - backendApiResponse = await envConnectionAPI(); - const connectionData = backendApiResponse.data; - const envCredentials = { - uri: connectionData.data.uri, - password: atob(connectionData.data.password), - userName: connectionData.data.user_name, - database: connectionData.data.database, - // isReadonlyUser: connectionData.data.write_access, - isGds: connectionData.data.gds_status, - }; - const updated = updateSessionIfNeeded(envCredentials, session); - if (!updated) { - setUserCredentialsFromSession(session); // Using stored session if no update is needed - } - setConnectionStatus(!!connectionData.data.graph_connection); - setIsBackendConnected(true); - handleDisconnectButtonState(false); - } catch (error) { - console.error('Error in DEV session handling:', error); - handleDisconnectButtonState(true); - setOpenConnection((prev) => ({ ...prev, openPopUp: true })); - setErrorMessage(backendApiResponse?.data.error); + if (session && isDev) { + let backendApiResponse; + try { + backendApiResponse = await envConnectionAPI(); + const connectionData = backendApiResponse.data; + const envCredentials = { + uri: connectionData.data.uri, + password: atob(connectionData.data.password), + userName: connectionData.data.user_name, + database: connectionData.data.database, + // isReadonlyUser: connectionData.data.write_access, + isGds: connectionData.data.gds_status, + }; + const updated = updateSessionIfNeeded(envCredentials, session); + if (!updated) { + setUserCredentialsFromSession(session); // Using stored session if no update is needed } - } else { + setConnectionStatus(Boolean(connectionData.data.graph_connection)); + setIsBackendConnected(true); + handleDisconnectButtonState(false); + } catch (error) { + console.error('Error in DEV session handling:', error); + handleDisconnectButtonState(true); + setOpenConnection((prev) => ({ ...prev, openPopUp: true })); + setErrorMessage(backendApiResponse?.data.error); + } + }else{ // For PROD, picking the session values - setUserCredentialsFromSession(session); + setUserCredentialsFromSession(session as string); setConnectionStatus(true); setIsBackendConnected(true); handleDisconnectButtonState(true); - } return; } // Handle case where no session exists @@ -214,7 +211,7 @@ const PageLayout: React.FC = () => { isGDS: credentials.isGds, }) ); - setConnectionStatus(!!connectionData.graph_connection); + setConnectionStatus(Boolean(connectionData.graph_connection)); setIsBackendConnected(true); handleDisconnectButtonState(false); } catch (error) { From 08a97554e86e2ae2854cdc6f60b2d6ec3769d166 Mon Sep 17 00:00:00 2001 From: aashipandya <156318202+aashipandya@users.noreply.github.com> Date: Thu, 28 Nov 2024 11:54:29 +0530 Subject: [PATCH 269/292] combining one chunk (#901) * combining one chunk * updated llm.py * updated llm.py --- backend/src/llm.py | 5 ++--- backend/src/shared/common_fn.py | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/backend/src/llm.py b/backend/src/llm.py index bfb2a7abc..de50fa181 100644 --- a/backend/src/llm.py +++ b/backend/src/llm.py @@ -18,7 +18,6 @@ import google.auth from src.shared.constants import MODEL_VERSIONS, PROMPT_TO_ALL_LLMs - def get_llm(model: str): """Retrieve the specified language model based on the model name.""" env_key = "LLM_MODEL_CONFIG_" + model @@ -201,8 +200,8 @@ async def get_graph_document_list( async def get_graph_from_llm(model, chunkId_chunkDoc_list, allowedNodes, allowedRelationship): llm, model_name = get_llm(model) - #combined_chunk_document_list = get_combined_chunks(chunkId_chunkDoc_list) - combined_chunk_document_list = get_chunk_id_as_doc_metadata(chunkId_chunkDoc_list) + combined_chunk_document_list = get_combined_chunks(chunkId_chunkDoc_list) + #combined_chunk_document_list = get_chunk_id_as_doc_metadata(chunkId_chunkDoc_list) if allowedNodes is None or allowedNodes=="": allowedNodes =[] diff --git a/backend/src/shared/common_fn.py b/backend/src/shared/common_fn.py index e6de7a583..916e01e89 100644 --- a/backend/src/shared/common_fn.py +++ b/backend/src/shared/common_fn.py @@ -60,7 +60,7 @@ def get_chunk_and_graphDocument(graph_document_list, chunkId_chunkDoc_list): logging.info("creating list of chunks and graph documents in get_chunk_and_graphDocument func") lst_chunk_chunkId_document=[] for graph_document in graph_document_list: - for chunk_id in graph_document.source.metadata['chunk_id'] : + for chunk_id in graph_document.source.metadata['combined_chunk_ids'] : lst_chunk_chunkId_document.append({'graph_doc':graph_document,'chunk_id':chunk_id}) return lst_chunk_chunkId_document From 3774a86875d07ed80dcffe5fb0ee6a8b1631cb6c Mon Sep 17 00:00:00 2001 From: kaustubh-darekar Date: Thu, 28 Nov 2024 12:43:55 +0530 Subject: [PATCH 270/292] Delete query refined to delete all related nodes of file (#904) --- backend/score.py | 2 +- backend/src/graphDB_dataAccess.py | 30 ++++++++++++++++-------------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/backend/score.py b/backend/score.py index a64d22fca..02ca99238 100644 --- a/backend/score.py +++ b/backend/score.py @@ -317,7 +317,7 @@ async def post_processing(uri=Form(), userName=Form(), password=Form(), database try: graph = create_graph_database_connection(uri, userName, password, database) tasks = set(map(str.strip, json.loads(tasks))) - count_response = "" + count_response = [] start = time.time() if "materialize_text_chunk_similarities" in tasks: await asyncio.to_thread(update_graph, graph) diff --git a/backend/src/graphDB_dataAccess.py b/backend/src/graphDB_dataAccess.py index bab2bc57f..4c2e6435b 100644 --- a/backend/src/graphDB_dataAccess.py +++ b/backend/src/graphDB_dataAccess.py @@ -283,16 +283,18 @@ def delete_file_from_graph(self, filenames, source_types, deleteEntities:str, me return count(*) as deletedChunks """ query_to_delete_document_and_entities=""" - match (d:Document) where d.fileName IN $filename_list and d.fileSource in $source_types_list - detach delete d - with collect(d) as documents - unwind documents as d - match (d)<-[:PART_OF]-(c:Chunk) - detach delete c - with * - match (c)-[:HAS_ENTITY]->(e) - where not exists { (e)<-[:HAS_ENTITY]-()-[:PART_OF]->(d2) where not d2 in documents } - detach delete e + MATCH (d:Document) + WHERE d.fileName IN $filename_list AND d.fileSource IN $source_types_list + WITH COLLECT(d) as documents + UNWIND documents AS d + MATCH (d)<-[:PART_OF]-(c:Chunk) + WITH d, c, documents + OPTIONAL MATCH (c)-[:HAS_ENTITY]->(e) + WHERE NOT EXISTS { + MATCH (e)<-[:HAS_ENTITY]-(c2)-[:PART_OF]->(d2:Document) + WHERE NOT d2 IN documents + } + DETACH DELETE c, e, d """ query_to_delete_communities = """ MATCH (c:`__Community__`) @@ -301,9 +303,9 @@ def delete_file_from_graph(self, filenames, source_types, deleteEntities:str, me WITH * UNWIND range(1, $max_level) AS level - MATCH (c:`__Community__`) - WHERE c.level = level AND NOT EXISTS { (c)<-[:PARENT_COMMUNITY]-(child) } - DETACH DELETE c + MATCH (c1:`__Community__`) + WHERE c1.level = level AND NOT EXISTS { (c1)<-[:PARENT_COMMUNITY]-(child) } + DETACH DELETE c1 """ param = {"filename_list" : filename_list, "source_types_list": source_types_list} community_param = {"max_level":MAX_COMMUNITY_LEVELS} @@ -456,7 +458,7 @@ def update_node_relationship_count(self,document_name): if (not document_name) and (community_flag): result = self.execute_query(NODEREL_COUNT_QUERY_WITH_COMMUNITY) elif (not document_name) and (not community_flag): - return None + return [] else: param = {"document_name": document_name} result = self.execute_query(NODEREL_COUNT_QUERY_WITHOUT_COMMUNITY, param) From bf7b739a2efb371c00e515f4a0f1d1a296c5245f Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Thu, 28 Nov 2024 10:04:43 +0000 Subject: [PATCH 271/292] readonly change --- frontend/src/components/Content.tsx | 33 +++++++++---------- frontend/src/components/Layout/PageLayout.tsx | 30 ++++++++--------- .../PostProcessingCheckList/index.tsx | 11 ++++--- frontend/src/context/UsersFiles.tsx | 17 ++++------ 4 files changed, 42 insertions(+), 49 deletions(-) diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 0b27db6b6..764caca0f 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -128,7 +128,8 @@ const Content: React.FC = ({ (async () => { showNormalToast(); try { - const response = await postProcessing(userCredentials as UserCredentials, postProcessingTasks); + const payload = isGdsActive ? postProcessingTasks : postProcessingTasks.filter((task) => task !== 'enable_communities'); + const response = await postProcessing(userCredentials as UserCredentials, payload); if (response.data.status === 'Success') { const communityfiles = response.data?.data; if (Array.isArray(communityfiles) && communityfiles.length) { @@ -508,9 +509,8 @@ const Content: React.FC = ({ const handleOpenGraphClick = () => { const bloomUrl = process.env.VITE_BLOOM_URL; const uriCoded = userCredentials?.uri.replace(/:\d+$/, ''); - const connectURL = `${uriCoded?.split('//')[0]}//${userCredentials?.userName}@${uriCoded?.split('//')[1]}:${ - userCredentials?.port ?? '7687' - }`; + const connectURL = `${uriCoded?.split('//')[0]}//${userCredentials?.userName}@${uriCoded?.split('//')[1]}:${userCredentials?.port ?? '7687' + }`; const encodedURL = encodeURIComponent(connectURL); const replacedUrl = bloomUrl?.replace('{CONNECT_URL}', encodedURL); window.open(replacedUrl, '_blank'); @@ -520,10 +520,10 @@ const Content: React.FC = ({ isLeftExpanded && isRightExpanded ? 'contentWithExpansion' : isRightExpanded - ? 'contentWithChatBot' - : !isLeftExpanded && !isRightExpanded - ? 'w-[calc(100%-128px)]' - : 'contentWithDropzoneExpansion'; + ? 'contentWithChatBot' + : !isLeftExpanded && !isRightExpanded + ? 'w-[calc(100%-128px)]' + : 'contentWithDropzoneExpansion'; const handleGraphView = () => { setOpenGraphView(true); @@ -555,12 +555,12 @@ const Content: React.FC = ({ return prev.map((f) => { return f.name === filename ? { - ...f, - status: 'Ready to Reprocess', - processingProgress: isStartFromBegining ? 0 : f.processingProgress, - nodesCount: isStartFromBegining ? 0 : f.nodesCount, - relationshipsCount: isStartFromBegining ? 0 : f.relationshipsCount, - } + ...f, + status: 'Ready to Reprocess', + processingProgress: isStartFromBegining ? 0 : f.processingProgress, + nodesCount: isStartFromBegining ? 0 : f.nodesCount, + relationshipsCount: isStartFromBegining ? 0 : f.relationshipsCount, + } : f; }); }); @@ -869,9 +869,8 @@ const Content: React.FC = ({ handleGenerateGraph={processWaitingFilesOnRefresh} > diff --git a/frontend/src/components/Layout/PageLayout.tsx b/frontend/src/components/Layout/PageLayout.tsx index 764f32e78..ac528f898 100644 --- a/frontend/src/components/Layout/PageLayout.tsx +++ b/frontend/src/components/Layout/PageLayout.tsx @@ -29,7 +29,7 @@ const PageLayout: React.FC = () => { chunksExistsWithDifferentDimension: false, }); const largedesktops = useMediaQuery(`(min-width:1440px )`); - const { userCredentials, connectionStatus } = useCredentials(); + const { userCredentials, connectionStatus, setIsReadOnlyUser } = useCredentials(); const [isLeftExpanded, setIsLeftExpanded] = useState(Boolean(largedesktops)); const [isRightExpanded, setIsRightExpanded] = useState(Boolean(largedesktops)); const [showChatBot, setShowChatBot] = useState(false); @@ -96,11 +96,7 @@ const PageLayout: React.FC = () => { parsedConnection.uri && parsedConnection.user && parsedConnection.password && - parsedConnection.database && - typeof parsedConnection.uri === 'string' && - typeof parsedConnection.user === 'string' && - typeof parsedConnection.password === 'string' && - typeof parsedConnection.database === 'string' + parsedConnection.database ) { setUserCredentials({ uri: parsedConnection.uri, @@ -109,7 +105,7 @@ const PageLayout: React.FC = () => { database: parsedConnection.database, }); setGdsActive(parsedConnection.isGDS); - // setIsReadOnlyUser(parsedConnection.isReadOnlyUser || false); + setIsReadOnlyUser(parsedConnection.isReadOnlyUser); } else { console.error('Invalid parsed session data:', parsedConnection); } @@ -136,7 +132,7 @@ const PageLayout: React.FC = () => { password: btoa(envCredentials.password), database: envCredentials.database, userDbVectorIndex: 384, - // isReadOnlyUser: envCredentials.isReadonlyUser, + isReadOnlyUser: envCredentials.isReadonlyUser, isGDS: envCredentials.isGds, }) ); @@ -160,7 +156,7 @@ const PageLayout: React.FC = () => { password: atob(connectionData.data.password), userName: connectionData.data.user_name, database: connectionData.data.database, - // isReadonlyUser: connectionData.data.write_access, + isReadonlyUser: !connectionData.data.write_access, isGds: connectionData.data.gds_status, }; const updated = updateSessionIfNeeded(envCredentials, session); @@ -176,12 +172,12 @@ const PageLayout: React.FC = () => { setOpenConnection((prev) => ({ ...prev, openPopUp: true })); setErrorMessage(backendApiResponse?.data.error); } - }else{ - // For PROD, picking the session values - setUserCredentialsFromSession(session as string); - setConnectionStatus(true); - setIsBackendConnected(true); - handleDisconnectButtonState(true); + } else { + // For PROD, picking the session values + setUserCredentialsFromSession(session as string); + setConnectionStatus(true); + setIsBackendConnected(true); + handleDisconnectButtonState(true); return; } // Handle case where no session exists @@ -195,7 +191,7 @@ const PageLayout: React.FC = () => { password: atob(connectionData.password), userName: connectionData.user_name, database: connectionData.database, - // isReadonlyUser: connectionData.write_access, + isReadonlyUser: !connectionData.write_access, isGds: connectionData.gds_status, }; setUserCredentials(credentials); @@ -207,7 +203,7 @@ const PageLayout: React.FC = () => { password: btoa(credentials.password), database: credentials.database, userDbVectorIndex: 384, - // isReadOnlyUser: credentials.isReadonlyUser, + isReadOnlyUser: credentials.isReadonlyUser, isGDS: credentials.isGds, }) ); diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/index.tsx index d2b721995..d5ebc04a2 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/index.tsx @@ -9,9 +9,6 @@ export default function PostProcessingCheckList() { const tablet = useMediaQuery(`(min-width:${breakpoints.xs}) and (max-width: ${breakpoints.lg})`); const { postProcessingTasks, setPostProcessingTasks } = useFileContext(); const { isGdsActive } = useCredentials(); - const handleCheckboxChange = (jobTitle: string, isChecked: boolean) => { - setPostProcessingTasks((prev) => (isChecked ? [...prev, jobTitle] : prev.filter((task) => task !== jobTitle))); - }; return (
          @@ -40,8 +37,14 @@ export default function PostProcessingCheckList() { ? isGdsActive && postProcessingTasks.includes(job.title) : postProcessingTasks.includes(job.title) } + onChange={(e) => { + if (e.target.checked) { + setPostProcessingTasks((prev) => [...prev, job.title]); + } else { + setPostProcessingTasks((prev) => prev.filter((s) => s !== job.title)); + } + }} isDisabled={isCreateCommunities && !isGdsActive} - onChange={(e) => handleCheckboxChange(job.title, e.target.checked)} ariaLabel='checkbox-postProcessing' /> {job.description} diff --git a/frontend/src/context/UsersFiles.tsx b/frontend/src/context/UsersFiles.tsx index 92f4a4b77..4a58ca5dc 100644 --- a/frontend/src/context/UsersFiles.tsx +++ b/frontend/src/context/UsersFiles.tsx @@ -35,17 +35,12 @@ const FileContextProvider: FC = ({ children }) => { triggeredFrom: '', show: false, }); - const [postProcessingTasks, setPostProcessingTasks] = useState(() => { - const tasks = [ - 'materialize_text_chunk_similarities', - 'enable_hybrid_search_and_fulltext_search_in_bloom', - 'materialize_entity_similarities', - ]; - if (isGdsActive) { - tasks.push('enable_communities'); - } - return tasks; - }); + const [postProcessingTasks, setPostProcessingTasks] = useState([ + 'materialize_text_chunk_similarities', + 'enable_hybrid_search_and_fulltext_search_in_bloom', + 'materialize_entity_similarities', + 'enable_communities', + ]); const [processedCount, setProcessedCount] = useState(0); const [postProcessingVal, setPostProcessingVal] = useState(false); From f4e593ebd1d047b35d83ad732141eb009aba2d4b Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Mon, 2 Dec 2024 13:38:48 +0530 Subject: [PATCH 272/292] Prod v6 fix (#909) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Staging to main (#735) * Dev (#537) * format fixes and graph schema indication fix * Update README.md * added chat modes variable in env updated the readme * spell fix * added the chat mode in env table * added the logos * fixed the overflow issues * removed the extra fix * Fixed specific scenario "when the text from schema closes it should reopen the previous modal" * readme changes * removed dev console logs * added new retrieval query (#533) * format fixes and tab rendering fix * fixed the setting modal reopen issue --------- Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * disabled the sumbit buttom on loading * Deduplication tab (#566) * de-duplication API * Update De-Duplicate query * created the Deduplication tab * added the API service * added the removeable tags for similar nodes in deduplication tab * Integrate Tag * added GraphLabel * added loader state * added the merge service * integrated the merge API * Merge Query issue fixed * Auto refresh the duplicate nodes after merging operation * added the description for de duplication * reset on merging --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Update frontend_docs.adoc (#538) * Update frontend_docs.adoc * doc update * Images * Images folder change * Images folder change * test image * Update frontend_docs.adoc * image change * Update frontend_docs.adoc * Update frontend_docs.adoc * added the Graph Mode SS * added the Query SS * Update frontend_docs.adoc * conflics fix * conflict fix * Update frontend_docs.adoc --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * updated langchain versions (#565) * Update the De-Duplication query * Node relationship id type none issue (#547) * de-duplication API * Update De-Duplicate query * Issue fixed Nodes,Relationship Id and Type None or Blank * added the tooltips * type fix * Unneccory import * added score threshold and added some error handling (#571) * Update requirements.txt * Tooltip and other UI fixes (#572) * Staging To Main (#495) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * Dev (#433) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env * DEV to STAGING (#461) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * DEV to STAGING (#462) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * added upload api * changed the dropzone error message * Dev to staging (#466) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env * added upload api * changed the dropzone error message --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-auth… * Update FileTable.tsx * merge changes * Update README.md * Update README.md * Update README.md * Update README.md * Graph visualization improvement and chunk text details (#860) * Update README.md * Dev to staging (#859) * processing count updated on cancel * format fixes * remove whitespace for enviroment variable which due to an error "xxx may not contain whitespace" (#707) * updated disconnected nodes * updated disconnected nodes * fix: Processed count update on failed condition * added disconnected and up nodes * removed __Entity__ labels * removed graph_object * removed graph object in the function * resetting the alert message on success scenario * Modified queries * populate graph schema * not clearing the password when there is error scenario * fixed the vector index loading issue * fix: empty credentials payload for recreate vector index api * chatbot status (#676) * chatbot status * connection status check for ASK button * refresh disable check * review comment resolved * format fixes * added properties and modified to entity labels * Post processing call after all files completion (#716) * Dev To STAGING (#532) * format fixes and graph schema indication fix * Update README.md * added chat modes variable in env updated the readme * spell fix * added the chat mode in env table * added the logos * fixed the overflow issues * removed the extra fix * Fixed specific scenario "when the text from schema closes it should reopen the previous modal" * readme changes * removed dev console logs * added new retrieval query (#533) * format fixes and tab rendering fix * fixed the setting modal reopen issue --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Dev (#535) * format fixes and graph schema indication fix * Update README.md * added chat modes variable in env updated the readme * spell fix * added the chat mode in env table * added the logos * fixed the overflow issues * removed the extra fix * Fixed specific scenario "when the text from schema closes it should reopen the previous modal" * readme changes * removed dev console logs * added new retrieval query (#533) * format fixes and tab rendering fix * fixed the setting modal reopen issue --------- Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Dev (#537) * format fixes and graph schema indication fix * Update README.md * added chat modes variable in env updated the readme * spell fix * added the chat mode in env table * added the logos * fixed the overflow issues * removed the extra fix * Fixed specific scenario "when the text from schema closes it should reopen the previous modal" * readme changes * removed dev console logs * added new retrieval query (#533) * format fixes and tab rendering fix * fixed the setting modal reopen issue --------- Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Fix typo: correct 'josn_obj' to 'json_obj' (#697) * Staging To Main (#495) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * Dev (#433) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env * DEV to STAGING (#461) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * DEV to STAGING (#462) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * added upload api * changed the dropzone error message * Dev to staging (#466) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * for… * enable communities removed and delete queries updated * nginx security headers * removed parameter to include chunk nodes as entity source * Ready to reprocess * communities fix * dependency fix Reprocess fix * icon size fix * z index fix * icon fix * icon gap fix * upload status * Checkbox fix * fix: table issue chat bot clear issue * new document deletion, 2nd level community deletion handled * claer history * graph info and delete query update * format changes --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: Ikko Eltociear Ashimine Co-authored-by: Jayanth T Co-authored-by: Jayanth T Co-authored-by: Jerome Choo Co-authored-by: jeromechoo Co-authored-by: Michael Hunger Co-authored-by: Kain Shu <44948284+Kain-90@users.noreply.github.com> Co-authored-by: destiny966113 <90891243+destiny966113@users.noreply.github.com> Co-authored-by: Pravesh1988 Co-authored-by: edenbuaa Co-authored-by: kaustubh-darekar Co-authored-by: a-s-poorna --- backend/score.py | 1 - backend/src/graphDB_dataAccess.py | 41 +- frontend/Dockerfile | 2 +- frontend/nginx/nginx.prod.conf | 42 +- frontend/package.json | 4 +- frontend/src/App.css | 4 +- .../src/components/ChatBot/ChatInfoModal.tsx | 2 +- frontend/src/components/ChatBot/Chatbot.tsx | 12 +- .../components/ChatBot/CommunitiesInfo.tsx | 5 +- .../src/components/ChatBot/EntitiesInfo.tsx | 4 +- frontend/src/components/Content.tsx | 35 +- frontend/src/components/FileTable.tsx | 22 - .../components/Graph/GraphPropertiesTable.tsx | 2 +- frontend/src/components/Layout/Header.tsx | 2 +- frontend/src/components/Layout/PageLayout.tsx | 8 +- .../components/Popups/ChunkPopUp/index.tsx | 1 - .../Deduplication/index.tsx | 6 +- .../DeleteTabForOrphanNodes/index.tsx | 2 +- .../SelectedJobList.tsx | 4 +- .../Popups/RetryConfirmation/Index.tsx | 2 +- frontend/src/context/UsersFiles.tsx | 2 +- frontend/src/utils/Utils.ts | 2 +- frontend/yarn.lock | 1685 ++++++++--------- 23 files changed, 934 insertions(+), 956 deletions(-) diff --git a/backend/score.py b/backend/score.py index 02ca99238..0c2884c25 100644 --- a/backend/score.py +++ b/backend/score.py @@ -924,7 +924,6 @@ async def fetch_chunktext( page_no: int = Form(1) ): try: - start = time.time() result = await asyncio.to_thread( get_chunktext_results, diff --git a/backend/src/graphDB_dataAccess.py b/backend/src/graphDB_dataAccess.py index 4c2e6435b..41a37631c 100644 --- a/backend/src/graphDB_dataAccess.py +++ b/backend/src/graphDB_dataAccess.py @@ -187,14 +187,11 @@ def check_gds_version(self): result = self.graph.query(gds_procedure_count) total_gds_procedures = result[0]['totalGdsProcedures'] if result else 0 - enable_communities = os.environ.get('ENABLE_COMMUNITIES','').upper() == "TRUE" - logging.info(f"Enable Communities {enable_communities}") - - if enable_communities and total_gds_procedures > 0: + if total_gds_procedures > 0: logging.info("GDS is available in the database.") return True else: - logging.info("Communities are disabled or GDS is not available in the database.") + logging.info("GDS is not available in the database.") return False except Exception as e: logging.error(f"An error occurred while checking GDS version: {e}") @@ -285,27 +282,31 @@ def delete_file_from_graph(self, filenames, source_types, deleteEntities:str, me query_to_delete_document_and_entities=""" MATCH (d:Document) WHERE d.fileName IN $filename_list AND d.fileSource IN $source_types_list - WITH COLLECT(d) as documents + WITH COLLECT(d) AS documents UNWIND documents AS d - MATCH (d)<-[:PART_OF]-(c:Chunk) - WITH d, c, documents - OPTIONAL MATCH (c)-[:HAS_ENTITY]->(e) + OPTIONAL MATCH (d)<-[:PART_OF]-(c:Chunk) + OPTIONAL MATCH (c:Chunk)-[:HAS_ENTITY]->(e) + WITH d, c, e, documents WHERE NOT EXISTS { MATCH (e)<-[:HAS_ENTITY]-(c2)-[:PART_OF]->(d2:Document) WHERE NOT d2 IN documents } - DETACH DELETE c, e, d - """ + WITH d, COLLECT(c) AS chunks, COLLECT(e) AS entities + FOREACH (chunk IN chunks | DETACH DELETE chunk) + FOREACH (entity IN entities | DETACH DELETE entity) + DETACH DELETE d + """ query_to_delete_communities = """ - MATCH (c:`__Community__`) - WHERE NOT EXISTS { ()-[:IN_COMMUNITY]->(c) } AND c.level = 0 - DETACH DELETE c - - WITH * - UNWIND range(1, $max_level) AS level - MATCH (c1:`__Community__`) - WHERE c1.level = level AND NOT EXISTS { (c1)<-[:PARENT_COMMUNITY]-(child) } - DETACH DELETE c1 + MATCH (c:`__Community__`) + WHERE c.level = 0 AND NOT EXISTS { ()-[:IN_COMMUNITY]->(c) } + DETACH DELETE c + WITH 1 AS dummy + UNWIND range(1, $max_level) AS level + CALL (level) { + MATCH (c:`__Community__`) + WHERE c.level = level AND NOT EXISTS { ()-[:PARENT_COMMUNITY]->(c) } + DETACH DELETE c + } """ param = {"filename_list" : filename_list, "source_types_list": source_types_list} community_param = {"max_level":MAX_COMMUNITY_LEVELS} diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 066563b30..5cbc3d8de 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -40,4 +40,4 @@ COPY --from=build /app/dist /usr/share/nginx/html COPY /nginx/nginx.${DEPLOYMENT_ENV}.conf /etc/nginx/templates/nginx.conf.template EXPOSE 8080 -CMD ["nginx", "-g", "daemon off;"] +CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/frontend/nginx/nginx.prod.conf b/frontend/nginx/nginx.prod.conf index f58585714..d9c369326 100644 --- a/frontend/nginx/nginx.prod.conf +++ b/frontend/nginx/nginx.prod.conf @@ -1,22 +1,22 @@ -server { - listen 8080; - add_header X-Frame-Options "DENY"; - add_header X-Content-Type-Options "nosniff"; - add_header Content-Security-Policy "connect-src 'self' ${VITE_BACKEND_API_URL} ${VITE_SEGMENT_API_URL}; - frame-src 'self' *.youtube.com *.wikipedia.org; - script-src 'self' 'unsafe-inline' https://accounts.google.com/gsi/client; - default-src 'self' *.${VITE_FRONTEND_HOSTNAME} data:; - style-src 'self' *.googleapis.com 'unsafe-inline';" always ; - gzip on; - location / { - root /usr/share/nginx/html; - index index.html index.htm; - try_files $uri $uri/ /index.html; - } - - error_page 401 403 404 index.html; - - location /public { - root /usr/local/var/www; - } +server { + listen 8080; + add_header X-Frame-Options "DENY"; + add_header X-Content-Type-Options "nosniff"; + add_header Content-Security-Policy "connect-src 'self' ${VITE_BACKEND_API_URL} ${VITE_SEGMENT_API_URL}; + frame-src 'self' *.youtube.com *.wikipedia.org; + script-src 'self' 'unsafe-inline' https://accounts.google.com/gsi/client; + default-src 'self' *.${VITE_FRONTEND_HOSTNAME} data:; + style-src 'self' *.googleapis.com 'unsafe-inline';" always ; + gzip on; + location / { + root /usr/share/nginx/html; + index index.html index.htm; + try_files $uri $uri/ /index.html; + } + + error_page 401 403 404 index.html; + + location /public { + root /usr/local/var/www; + } } \ No newline at end of file diff --git a/frontend/package.json b/frontend/package.json index 3c869ad59..846621f49 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -15,8 +15,8 @@ "@mui/material": "^5.15.10", "@mui/styled-engine": "^5.15.9", "@neo4j-devtools/word-color": "^0.0.8", - "@neo4j-ndl/base": "^3.0.14", - "@neo4j-ndl/react": "^3.0.23", + "@neo4j-ndl/base": "^3.0.16", + "@neo4j-ndl/react": "^3.0.30", "@neo4j-nvl/base": "^0.3.6", "@neo4j-nvl/react": "^0.3.6", "@react-oauth/google": "^0.12.1", diff --git a/frontend/src/App.css b/frontend/src/App.css index 70127b6af..93eab4ae5 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -58,7 +58,7 @@ } .contentWithChatBot { - width: calc(-528px + 100dvw); + width: calc(-512px + 100dvw); height: calc(100dvh - 58px); padding: 3px; display: flex; @@ -395,4 +395,4 @@ } .tbody-light .ndl-data-grid-tr:hover { --cell-background: rgb(226 227 229) !important; -} \ No newline at end of file +} diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index 1609f1eac..68c07227d 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -321,7 +321,7 @@ const ChatInfoModal: React.FC = ({ [activeChatmodes] ); return ( -
          +
          = (props) => { } else { setListMessages((prev) => prev.map((msg) => - (msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg) + msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg ) ); } @@ -264,7 +264,7 @@ const Chatbot: FC = (props) => { } else { setListMessages((prev) => prev.map((msg) => - (msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg) + msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg ) ); } @@ -273,7 +273,7 @@ const Chatbot: FC = (props) => { console.error(`API call failed for mode ${mode}:`, result.reason); setListMessages((prev) => prev.map((msg) => - (msg.id === chatbotMessageId + msg.id === chatbotMessageId ? { ...msg, modes: { @@ -281,7 +281,7 @@ const Chatbot: FC = (props) => { [mode]: { message: 'Failed to fetch response for this mode.', error: result.reason }, }, } - : msg) + : msg ) ); } @@ -294,7 +294,7 @@ const Chatbot: FC = (props) => { if (error instanceof Error) { setListMessages((prev) => prev.map((msg) => - (msg.id === chatbotMessageId + msg.id === chatbotMessageId ? { ...msg, isLoading: false, @@ -306,7 +306,7 @@ const Chatbot: FC = (props) => { }, }, } - : msg) + : msg ) ); } diff --git a/frontend/src/components/ChatBot/CommunitiesInfo.tsx b/frontend/src/components/ChatBot/CommunitiesInfo.tsx index 30d533193..48a72b86c 100644 --- a/frontend/src/components/ChatBot/CommunitiesInfo.tsx +++ b/frontend/src/components/ChatBot/CommunitiesInfo.tsx @@ -61,7 +61,10 @@ const CommunitiesInfo: FC = ({ loading, communities, mode }) =
      ) : ( - No Communities Found + + {' '} + No Communities Found + )} {openGraphView && ( = ({ loading, mode, graphonly_entities, in })}
    ) : ( - No Entities Found + + No Entities Found + )} {openGraphView && ( = ({ setProcessedCount, setchatModes, } = useFileContext(); - const [viewPoint, setViewPoint] = useState<'tableView' | 'showGraphView' | 'chatInfoView' | 'neighborView'>( 'tableView' ); @@ -128,7 +127,9 @@ const Content: React.FC = ({ (async () => { showNormalToast(); try { - const payload = isGdsActive ? postProcessingTasks : postProcessingTasks.filter((task) => task !== 'enable_communities'); + const payload = isGdsActive + ? postProcessingTasks + : postProcessingTasks.filter((task) => task !== 'enable_communities'); const response = await postProcessing(userCredentials as UserCredentials, payload); if (response.data.status === 'Success') { const communityfiles = response.data?.data; @@ -509,8 +510,9 @@ const Content: React.FC = ({ const handleOpenGraphClick = () => { const bloomUrl = process.env.VITE_BLOOM_URL; const uriCoded = userCredentials?.uri.replace(/:\d+$/, ''); - const connectURL = `${uriCoded?.split('//')[0]}//${userCredentials?.userName}@${uriCoded?.split('//')[1]}:${userCredentials?.port ?? '7687' - }`; + const connectURL = `${uriCoded?.split('//')[0]}//${userCredentials?.userName}@${uriCoded?.split('//')[1]}:${ + userCredentials?.port ?? '7687' + }`; const encodedURL = encodeURIComponent(connectURL); const replacedUrl = bloomUrl?.replace('{CONNECT_URL}', encodedURL); window.open(replacedUrl, '_blank'); @@ -520,10 +522,10 @@ const Content: React.FC = ({ isLeftExpanded && isRightExpanded ? 'contentWithExpansion' : isRightExpanded - ? 'contentWithChatBot' - : !isLeftExpanded && !isRightExpanded - ? 'w-[calc(100%-128px)]' - : 'contentWithDropzoneExpansion'; + ? 'contentWithChatBot' + : !isLeftExpanded && !isRightExpanded + ? 'w-[calc(100%-128px)]' + : 'contentWithDropzoneExpansion'; const handleGraphView = () => { setOpenGraphView(true); @@ -555,12 +557,12 @@ const Content: React.FC = ({ return prev.map((f) => { return f.name === filename ? { - ...f, - status: 'Ready to Reprocess', - processingProgress: isStartFromBegining ? 0 : f.processingProgress, - nodesCount: isStartFromBegining ? 0 : f.nodesCount, - relationshipsCount: isStartFromBegining ? 0 : f.relationshipsCount, - } + ...f, + status: 'Ready to Reprocess', + processingProgress: isStartFromBegining ? 0 : f.processingProgress, + nodesCount: isStartFromBegining ? 0 : f.nodesCount, + relationshipsCount: isStartFromBegining ? 0 : f.relationshipsCount, + } : f; }); }); @@ -869,8 +871,9 @@ const Content: React.FC = ({ handleGenerateGraph={processWaitingFilesOnRefresh} > diff --git a/frontend/src/components/FileTable.tsx b/frontend/src/components/FileTable.tsx index 53903d032..2cf1d7255 100644 --- a/frontend/src/components/FileTable.tsx +++ b/frontend/src/components/FileTable.tsx @@ -970,28 +970,6 @@ const FileTable = forwardRef((props, ref) => { }), [table] ); - useEffect(() => { - if (tableRef.current) { - // Component has content, calculate maximum height for table - // Observes the height of the content and calculates own height accordingly - const resizeObserver = new ResizeObserver((entries) => { - for (let index = 0; index < entries.length; index++) { - const entry = entries[index]; - const { height } = entry.contentRect; - const rowHeight = document?.getElementsByClassName('ndl-data-grid-td')?.[0]?.clientHeight ?? 69; - table.setPageSize(Math.floor(height / rowHeight)); - } - }); - - const [contentElement] = document.getElementsByClassName('ndl-data-grid-scrollable'); - resizeObserver.observe(contentElement); - - return () => { - // Stop observing content after cleanup - resizeObserver.unobserve(contentElement); - }; - } - }, []); const classNameCheck = isExpanded ? 'fileTableWithExpansion' : `filetable`; diff --git a/frontend/src/components/Graph/GraphPropertiesTable.tsx b/frontend/src/components/Graph/GraphPropertiesTable.tsx index 753c200fb..fcabb0103 100644 --- a/frontend/src/components/Graph/GraphPropertiesTable.tsx +++ b/frontend/src/components/Graph/GraphPropertiesTable.tsx @@ -16,10 +16,10 @@ const GraphPropertiesTable = ({ propertiesWithTypes }: GraphPropertiesTableProps
    {key} diff --git a/frontend/src/components/Layout/Header.tsx b/frontend/src/components/Layout/Header.tsx index b969401b3..2cd243b29 100644 --- a/frontend/src/components/Layout/Header.tsx +++ b/frontend/src/components/Layout/Header.tsx @@ -56,7 +56,7 @@ const Header: React.FC = ({ chatOnly, deleteOnClick, setOpenConnecti const userName = neo4jConnection.user; const { password } = neo4jConnection; const { database } = neo4jConnection; - const [,port]= uri.split(':'); + const [, port] = uri.split(':'); const encodedPassword = btoa(password); const chatUrl = `/chat-only?uri=${encodeURIComponent( uri diff --git a/frontend/src/components/Layout/PageLayout.tsx b/frontend/src/components/Layout/PageLayout.tsx index ac528f898..dca910e43 100644 --- a/frontend/src/components/Layout/PageLayout.tsx +++ b/frontend/src/components/Layout/PageLayout.tsx @@ -38,7 +38,6 @@ const PageLayout: React.FC = () => { const [shows3Modal, toggleS3Modal] = useReducer((s) => !s, false); const [showGCSModal, toggleGCSModal] = useReducer((s) => !s, false); const [showGenericModal, toggleGenericModal] = useReducer((s) => !s, false); - const toggleLeftDrawer = () => { if (largedesktops) { setIsLeftExpanded(!isLeftExpanded); @@ -92,12 +91,7 @@ const PageLayout: React.FC = () => { } try { const parsedConnection = JSON.parse(neo4jConnection); - if ( - parsedConnection.uri && - parsedConnection.user && - parsedConnection.password && - parsedConnection.database - ) { + if (parsedConnection.uri && parsedConnection.user && parsedConnection.password && parsedConnection.database) { setUserCredentials({ uri: parsedConnection.uri, userName: parsedConnection.user, diff --git a/frontend/src/components/Popups/ChunkPopUp/index.tsx b/frontend/src/components/Popups/ChunkPopUp/index.tsx index b8020c276..c0e2a016b 100644 --- a/frontend/src/components/Popups/ChunkPopUp/index.tsx +++ b/frontend/src/components/Popups/ChunkPopUp/index.tsx @@ -30,7 +30,6 @@ const ChunkPopUp = ({ const sortedChunksData = useMemo(() => { return chunks.sort((a, b) => a.position - b.position); }, [chunks]); - return ( diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx index 97c584b7c..df30c25c1 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx @@ -104,12 +104,12 @@ export default function DeduplicationTab() { const onRemove = (nodeid: string, similarNodeId: string) => { setDuplicateNodes((prev) => { return prev.map((d) => - (d.e.elementId === nodeid + d.e.elementId === nodeid ? { ...d, similar: d.similar.filter((n) => n.elementId != similarNodeId), } - : d) + : d ); }); }; @@ -143,7 +143,7 @@ export default function DeduplicationTab() { return (
    - (isGdsActive + isGdsActive ? postProcessingTasks.includes('enable_communities') ? postProcessingTasks : postProcessingTasks.filter((s) => s != 'enable_communities') - : postProcessingTasks.filter((s) => s != 'enable_communities')), + : postProcessingTasks.filter((s) => s != 'enable_communities'), [isGdsActive, postProcessingTasks] ); return ( diff --git a/frontend/src/components/Popups/RetryConfirmation/Index.tsx b/frontend/src/components/Popups/RetryConfirmation/Index.tsx index 4ae9b18eb..c6345a956 100644 --- a/frontend/src/components/Popups/RetryConfirmation/Index.tsx +++ b/frontend/src/components/Popups/RetryConfirmation/Index.tsx @@ -71,7 +71,7 @@ function RetryConfirmationDialog({ = ({ children }) => { const selectedNodeLabelstr = localStorage.getItem('selectedNodeLabels'); const selectedNodeRelsstr = localStorage.getItem('selectedRelationshipLabels'); const persistedQueue = localStorage.getItem('waitingQueue'); - const { userCredentials, isGdsActive } = useCredentials(); + const { userCredentials } = useCredentials(); const [files, setFiles] = useState<(File | null)[] | []>([]); const [filesData, setFilesData] = useState([]); const [queue, setQueue] = useState( diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index 7314c55e7..82217535d 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -395,7 +395,7 @@ export const isFileCompleted = (waitingFile: CustomFile, item: SourceNode) => waitingFile && item.status === 'Completed'; export const calculateProcessedCount = (prev: number, batchSize: number) => - (prev === batchSize ? batchSize - 1 : prev + 1); + prev === batchSize ? batchSize - 1 : prev + 1; export const isProcessingFileValid = (item: SourceNode, userCredentials: UserCredentials) => { return item.status === 'Processing' && item.fileName != undefined && userCredentials && userCredentials.database; diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 253a4e287..82c021a0e 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -505,9 +505,9 @@ tabbable "^6.0.0" "@floating-ui/react@^0.26.2": - version "0.26.27" - resolved "https://registry.yarnpkg.com/@floating-ui/react/-/react-0.26.27.tgz#402f7b4b2702650662705fe9cbe0f1d5607846a1" - integrity sha512-jLP72x0Kr2CgY6eTYi/ra3VA9LOkTo4C+DUTrbFgFOExKy3omYVmwMjNKqxAHdsnyLS96BIDLcO2SlnsNf8KUQ== + version "0.26.28" + resolved "https://registry.yarnpkg.com/@floating-ui/react/-/react-0.26.28.tgz#93f44ebaeb02409312e9df9507e83aab4a8c0dc7" + integrity sha512-yORQuuAtVpiRjpMhdc0wJj06b9JFjrYF4qp96j++v2NBpbi6SEGF7donUJ3TMieerQ6qVkAv1tgr7L4r5roTqw== dependencies: "@floating-ui/react-dom" "^2.1.2" "@floating-ui/utils" "^0.2.8" @@ -586,46 +586,33 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== -"@internationalized/date@^3.5.6": - version "3.5.6" - resolved "https://registry.yarnpkg.com/@internationalized/date/-/date-3.5.6.tgz#0833c2fa75efb3573f4e3bf10e3895f1019e87dd" - integrity sha512-jLxQjefH9VI5P9UQuqB6qNKnvFt1Ky1TPIzHGsIlCi7sZZoMR8SdYbBGRvM0y+Jtb+ez4ieBzmiAUcpmPYpyOw== +"@internationalized/date@^3.6.0": + version "3.6.0" + resolved "https://registry.yarnpkg.com/@internationalized/date/-/date-3.6.0.tgz#b30d43030bfed1855f20c9503606926d75bfdf64" + integrity sha512-+z6ti+CcJnRlLHok/emGEsWQhe7kfSmEW+/6qCzvKY67YPh7YOBfvc7+/+NXq+zJlbArg30tYpqLjNgcAYv2YQ== dependencies: "@swc/helpers" "^0.5.0" -"@internationalized/message@^3.1.5": - version "3.1.5" - resolved "https://registry.yarnpkg.com/@internationalized/message/-/message-3.1.5.tgz#7391bba7a0489022a099f5bc37eb161889d520c8" - integrity sha512-hjEpLKFlYA3m5apldLqzHqw531qqfOEq0HlTWdfyZmcloWiUbWsYXD6YTiUmQmOtarthzhdjCAwMVrB8a4E7uA== +"@internationalized/message@^3.1.6": + version "3.1.6" + resolved "https://registry.yarnpkg.com/@internationalized/message/-/message-3.1.6.tgz#e5a832788a17214bfb3e5bbf5f0e23ed2f568ad7" + integrity sha512-JxbK3iAcTIeNr1p0WIFg/wQJjIzJt9l/2KNY/48vXV7GRGZSv3zMxJsce008fZclk2cDC8y0Ig3odceHO7EfNQ== dependencies: "@swc/helpers" "^0.5.0" intl-messageformat "^10.1.0" -"@internationalized/number@^3.5.4": - version "3.5.4" - resolved "https://registry.yarnpkg.com/@internationalized/number/-/number-3.5.4.tgz#db1c648fa191b28062c2f4fd81fac89777ad3e91" - integrity sha512-h9huwWjNqYyE2FXZZewWqmCdkw1HeFds5q4Siuoms3hUQC5iPJK3aBmkFZoDSLN4UD0Bl8G22L/NdHpeOr+/7A== +"@internationalized/number@^3.6.0": + version "3.6.0" + resolved "https://registry.yarnpkg.com/@internationalized/number/-/number-3.6.0.tgz#dc6ba20c41b25eb605f1d5cac7d8668e9022c224" + integrity sha512-PtrRcJVy7nw++wn4W2OuePQQfTqDzfusSuY1QTtui4wa7r+rGVtR75pO8CyKvHvzyQYi3Q1uO5sY0AsB4e65Bw== dependencies: "@swc/helpers" "^0.5.0" -"@internationalized/string@^3.2.4": - version "3.2.4" - resolved "https://registry.yarnpkg.com/@internationalized/string/-/string-3.2.4.tgz#e05ddd93a7b83e936940c83f5b3a8597d8c3a370" - integrity sha512-BcyadXPn89Ae190QGZGDUZPqxLj/xsP4U1Br1oSy8yfIjmpJ8cJtGYleaodqW/EmzFjwELtwDojLkf3FhV6SjA== +"@internationalized/string@^3.2.4", "@internationalized/string@^3.2.5": + version "3.2.5" + resolved "https://registry.yarnpkg.com/@internationalized/string/-/string-3.2.5.tgz#2f387b256e79596a2e62ddd5e15c619fe241189c" + integrity sha512-rKs71Zvl2OKOHM+mzAFMIyqR5hI1d1O6BBkMK2/lkfg3fkmVh9Eeg0awcA8W2WqYqDOv6a86DIOlFpggwLtbuw== dependencies: - "@swc/helpers" "^0.5.0" - -"@isaacs/cliui@^8.0.2": - version "8.0.2" - resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" - integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== - dependencies: - string-width "^5.1.2" - string-width-cjs "npm:string-width@^4.2.0" - strip-ansi "^7.0.1" - strip-ansi-cjs "npm:strip-ansi@^6.0.1" - wrap-ansi "^8.1.0" - wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" "@jridgewell/gen-mapping@^0.3.2", "@jridgewell/gen-mapping@^0.3.5": version "0.3.5" @@ -760,15 +747,15 @@ "@types/chroma-js" "2.1.4" chroma-js "2.4.2" -"@neo4j-ndl/base@^3.0.14": - version "3.0.14" - resolved "https://registry.yarnpkg.com/@neo4j-ndl/base/-/base-3.0.14.tgz#158db809cec3c986cf9170f8967f37cbf5740f61" - integrity sha512-GVRuibSXvhKsJMJH4J7ROQ1yyvNhvyiPBGewFJHR3fspxi/nKV4dh0jCspdSEdrtAhdhI5VGdwQlSDJREjEPzA== +"@neo4j-ndl/base@^3.0.16": + version "3.0.16" + resolved "https://registry.yarnpkg.com/@neo4j-ndl/base/-/base-3.0.16.tgz#8e20072c14f6249e901a2696ebdbd5ed60e63438" + integrity sha512-elmtzwdF4AxMHNhLnZJL4V3v6QH5Sv+6RZ1V4HY819w49f7cY3Sd1BYdA9/fu5ADrDOzY+fzPc5BUlIuYxbYaw== -"@neo4j-ndl/react@^3.0.23": - version "3.0.23" - resolved "https://registry.yarnpkg.com/@neo4j-ndl/react/-/react-3.0.23.tgz#07b1c24f5ca5adee630318b8a0a67419b5736a53" - integrity sha512-/szMXh/2ROpAVrNrNTOP4IK5eMWB5hRNMHXfu7NJOyqYAhWJlMkjZQClGEM7qvBAX6RoV8mmRWafquWMZhdnoA== +"@neo4j-ndl/react@^3.0.30": + version "3.0.30" + resolved "https://registry.yarnpkg.com/@neo4j-ndl/react/-/react-3.0.30.tgz#9476f95914876dbc7dc16a137ca53ea2b58ceb55" + integrity sha512-V4fwM56qM1JXeFOQfQLxvyYAaZm7uhmp9dfx2zSM41tIkS4gDTKlW4tIZG5bKQpE3LKAANpKjlQxsa14w14/5A== dependencies: "@dnd-kit/core" "6.1.0" "@dnd-kit/sortable" "8.0.0" @@ -778,8 +765,6 @@ "@table-nav/core" "0.0.7" "@table-nav/react" "0.0.7" classnames "2.5.1" - d3 "7.9.0" - d3-shape "3.2.0" date-fns "4.1.0" detect-browser "5.3.0" re-resizable "6.10.0" @@ -877,583 +862,596 @@ integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== "@react-aria/breadcrumbs@^3.5.17": - version "3.5.18" - resolved "https://registry.yarnpkg.com/@react-aria/breadcrumbs/-/breadcrumbs-3.5.18.tgz#72133bdb61744f538fba41f9e06864f980860e1b" - integrity sha512-JRc6nAwQsjqsPw/3MlGwJcVo9ACZDbCOwWNNEnj8mR0fQopJO5xliq3qVzxDRZjdYrVUfTTyKXuepv/jMB1Y6Q== - dependencies: - "@react-aria/i18n" "^3.12.3" - "@react-aria/link" "^3.7.6" - "@react-aria/utils" "^3.25.3" - "@react-types/breadcrumbs" "^3.7.8" - "@react-types/shared" "^3.25.0" + version "3.5.19" + resolved "https://registry.yarnpkg.com/@react-aria/breadcrumbs/-/breadcrumbs-3.5.19.tgz#e0a67e0e7017089fa0ee5eadd51a6da505b94cd4" + integrity sha512-mVngOPFYVVhec89rf/CiYQGTfaLRfHFtX+JQwY7sNYNqSA+gO8p4lNARe3Be6bJPgH+LUQuruIY9/ZDL6LT3HA== + dependencies: + "@react-aria/i18n" "^3.12.4" + "@react-aria/link" "^3.7.7" + "@react-aria/utils" "^3.26.0" + "@react-types/breadcrumbs" "^3.7.9" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" "@react-aria/button@^3.10.0": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@react-aria/button/-/button-3.10.1.tgz#348879949a612a90c056f69079edb1c1414f7ff1" - integrity sha512-1vkRsjdvJrJleK73u7ClrW4Fw3mtr2hIs8M2yLZUpLoqHXnIYJwmeEMtzwyPFYKBc5jaHcGXw45any7Puy1aFA== - dependencies: - "@react-aria/focus" "^3.18.4" - "@react-aria/interactions" "^3.22.4" - "@react-aria/utils" "^3.25.3" - "@react-stately/toggle" "^3.7.8" - "@react-types/button" "^3.10.0" - "@react-types/shared" "^3.25.0" + version "3.11.0" + resolved "https://registry.yarnpkg.com/@react-aria/button/-/button-3.11.0.tgz#cb7790db23949ec9c1e698fa531ee5471cf2b515" + integrity sha512-b37eIV6IW11KmNIAm65F3SEl2/mgj5BrHIysW6smZX3KoKWTGYsYfcQkmtNgY0GOSFfDxMCoolsZ6mxC00nSDA== + dependencies: + "@react-aria/focus" "^3.19.0" + "@react-aria/interactions" "^3.22.5" + "@react-aria/toolbar" "3.0.0-beta.11" + "@react-aria/utils" "^3.26.0" + "@react-stately/toggle" "^3.8.0" + "@react-types/button" "^3.10.1" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" "@react-aria/calendar@^3.5.12": - version "3.5.13" - resolved "https://registry.yarnpkg.com/@react-aria/calendar/-/calendar-3.5.13.tgz#7cf8787b521c8fc193550ce27acc114390502b16" - integrity sha512-BJV5IwIH4UPDa6/HRTOBcM1wC+/6p823VrbocV9mr+rt5cCnuh+cqcCQKqUSEbfaTMPrmabjBuEaQIvqjLRYUA== - dependencies: - "@internationalized/date" "^3.5.6" - "@react-aria/i18n" "^3.12.3" - "@react-aria/interactions" "^3.22.4" - "@react-aria/live-announcer" "^3.4.0" - "@react-aria/utils" "^3.25.3" - "@react-stately/calendar" "^3.5.5" - "@react-types/button" "^3.10.0" - "@react-types/calendar" "^3.4.10" - "@react-types/shared" "^3.25.0" + version "3.6.0" + resolved "https://registry.yarnpkg.com/@react-aria/calendar/-/calendar-3.6.0.tgz#d5e7cf4beb8724648a7042dbc5bb519de4351906" + integrity sha512-tZ3nd5DP8uxckbj83Pt+4RqgcTWDlGi7njzc7QqFOG2ApfnYDUXbIpb/Q4KY6JNlJskG8q33wo0XfOwNy8J+eg== + dependencies: + "@internationalized/date" "^3.6.0" + "@react-aria/i18n" "^3.12.4" + "@react-aria/interactions" "^3.22.5" + "@react-aria/live-announcer" "^3.4.1" + "@react-aria/utils" "^3.26.0" + "@react-stately/calendar" "^3.6.0" + "@react-types/button" "^3.10.1" + "@react-types/calendar" "^3.5.0" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" "@react-aria/checkbox@^3.14.7": - version "3.14.8" - resolved "https://registry.yarnpkg.com/@react-aria/checkbox/-/checkbox-3.14.8.tgz#b4117f420e44d3a2693029453bb673d729c14f99" - integrity sha512-0qPJ3fiQQm7tiMHmIhR9iokr/MhhI2h6OWX/pDeIy/Gj63WSVk+Cka3NUhgMRGkguHKDZPKaFjK1oZQsXhCThQ== - dependencies: - "@react-aria/form" "^3.0.10" - "@react-aria/interactions" "^3.22.4" - "@react-aria/label" "^3.7.12" - "@react-aria/toggle" "^3.10.9" - "@react-aria/utils" "^3.25.3" - "@react-stately/checkbox" "^3.6.9" - "@react-stately/form" "^3.0.6" - "@react-stately/toggle" "^3.7.8" - "@react-types/checkbox" "^3.8.4" - "@react-types/shared" "^3.25.0" + version "3.15.0" + resolved "https://registry.yarnpkg.com/@react-aria/checkbox/-/checkbox-3.15.0.tgz#4d224b71c65d6a079ff935ab22c806323f84b746" + integrity sha512-z/8xd4em7o0MroBXwkkwv7QRwiJaA1FwqMhRUb7iqtBGP2oSytBEDf0N7L09oci32a1P4ZPz2rMK5GlLh/PD6g== + dependencies: + "@react-aria/form" "^3.0.11" + "@react-aria/interactions" "^3.22.5" + "@react-aria/label" "^3.7.13" + "@react-aria/toggle" "^3.10.10" + "@react-aria/utils" "^3.26.0" + "@react-stately/checkbox" "^3.6.10" + "@react-stately/form" "^3.1.0" + "@react-stately/toggle" "^3.8.0" + "@react-types/checkbox" "^3.9.0" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" "@react-aria/color@^3.0.0": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@react-aria/color/-/color-3.0.1.tgz#3c78693a1a7a33ca421da9c637b696ec9dee601b" - integrity sha512-7hTCdXCU2/qpZuIrJcVr+s87C2MqHfi9Y461gMza5DjdUzlcy480UZ/iknbw82C0a+oVo08D/bnQctEjja05pw== - dependencies: - "@react-aria/i18n" "^3.12.3" - "@react-aria/interactions" "^3.22.4" - "@react-aria/numberfield" "^3.11.8" - "@react-aria/slider" "^3.7.13" - "@react-aria/spinbutton" "^3.6.9" - "@react-aria/textfield" "^3.14.10" - "@react-aria/utils" "^3.25.3" - "@react-aria/visually-hidden" "^3.8.17" - "@react-stately/color" "^3.8.0" - "@react-stately/form" "^3.0.6" - "@react-types/color" "^3.0.0" - "@react-types/shared" "^3.25.0" + version "3.0.2" + resolved "https://registry.yarnpkg.com/@react-aria/color/-/color-3.0.2.tgz#3abeb7e9fa9756e1823e513921e04dcaa47b25cc" + integrity sha512-dSM5qQRcR1gRGYCBw0IGRmc29gjfoht3cQleKb8MMNcgHYa2oi5VdCs2yKXmYFwwVC6uPtnlNy9S6e0spqdr+w== + dependencies: + "@react-aria/i18n" "^3.12.4" + "@react-aria/interactions" "^3.22.5" + "@react-aria/numberfield" "^3.11.9" + "@react-aria/slider" "^3.7.14" + "@react-aria/spinbutton" "^3.6.10" + "@react-aria/textfield" "^3.15.0" + "@react-aria/utils" "^3.26.0" + "@react-aria/visually-hidden" "^3.8.18" + "@react-stately/color" "^3.8.1" + "@react-stately/form" "^3.1.0" + "@react-types/color" "^3.0.1" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" "@react-aria/combobox@^3.10.4": - version "3.10.5" - resolved "https://registry.yarnpkg.com/@react-aria/combobox/-/combobox-3.10.5.tgz#2530829da5e3bdae1ab3f42288f85ce683654830" - integrity sha512-1cjBJXWYuR0de+9IEU1MOer3H5FSlbrdaqlWo+M6vvMymBL2OjjwXiG3LY1mR65ZwHoTswXzt6/mujUKaxk5vw== - dependencies: - "@react-aria/i18n" "^3.12.3" - "@react-aria/listbox" "^3.13.5" - "@react-aria/live-announcer" "^3.4.0" - "@react-aria/menu" "^3.15.5" - "@react-aria/overlays" "^3.23.4" - "@react-aria/selection" "^3.20.1" - "@react-aria/textfield" "^3.14.10" - "@react-aria/utils" "^3.25.3" - "@react-stately/collections" "^3.11.0" - "@react-stately/combobox" "^3.10.0" - "@react-stately/form" "^3.0.6" - "@react-types/button" "^3.10.0" - "@react-types/combobox" "^3.13.0" - "@react-types/shared" "^3.25.0" + version "3.11.0" + resolved "https://registry.yarnpkg.com/@react-aria/combobox/-/combobox-3.11.0.tgz#9489aaad342d092bf1fe1c4c382f6714316ac1c4" + integrity sha512-s88YMmPkMO1WSoiH1KIyZDLJqUwvM2wHXXakj3cYw1tBHGo4rOUFq+JWQIbM5EDO4HOR4AUUqzIUd0NO7t3zyg== + dependencies: + "@react-aria/i18n" "^3.12.4" + "@react-aria/listbox" "^3.13.6" + "@react-aria/live-announcer" "^3.4.1" + "@react-aria/menu" "^3.16.0" + "@react-aria/overlays" "^3.24.0" + "@react-aria/selection" "^3.21.0" + "@react-aria/textfield" "^3.15.0" + "@react-aria/utils" "^3.26.0" + "@react-stately/collections" "^3.12.0" + "@react-stately/combobox" "^3.10.1" + "@react-stately/form" "^3.1.0" + "@react-types/button" "^3.10.1" + "@react-types/combobox" "^3.13.1" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" "@react-aria/datepicker@^3.11.3": - version "3.11.4" - resolved "https://registry.yarnpkg.com/@react-aria/datepicker/-/datepicker-3.11.4.tgz#f0a927e7958cd341de8d4ccd78cf28ec69ecbdf6" - integrity sha512-TXe1TB/pSwrIQ5BIDr6NCAYjBaKgLN6cP5DlAihywHzqxbM6vO8GU6qbrZNSBrtfzZnrR/4z66Vlw6rhznLnqQ== - dependencies: - "@internationalized/date" "^3.5.6" - "@internationalized/number" "^3.5.4" - "@internationalized/string" "^3.2.4" - "@react-aria/focus" "^3.18.4" - "@react-aria/form" "^3.0.10" - "@react-aria/i18n" "^3.12.3" - "@react-aria/interactions" "^3.22.4" - "@react-aria/label" "^3.7.12" - "@react-aria/spinbutton" "^3.6.9" - "@react-aria/utils" "^3.25.3" - "@react-stately/datepicker" "^3.10.3" - "@react-stately/form" "^3.0.6" - "@react-types/button" "^3.10.0" - "@react-types/calendar" "^3.4.10" - "@react-types/datepicker" "^3.8.3" - "@react-types/dialog" "^3.5.13" - "@react-types/shared" "^3.25.0" + version "3.12.0" + resolved "https://registry.yarnpkg.com/@react-aria/datepicker/-/datepicker-3.12.0.tgz#a82ff3ebd3ead20a00096d082c1e6be47bbd5886" + integrity sha512-VYNXioLfddIHpwQx211+rTYuunDmI7VHWBRetCpH3loIsVFuhFSRchTQpclAzxolO3g0vO7pMVj9VYt7Swp6kg== + dependencies: + "@internationalized/date" "^3.6.0" + "@internationalized/number" "^3.6.0" + "@internationalized/string" "^3.2.5" + "@react-aria/focus" "^3.19.0" + "@react-aria/form" "^3.0.11" + "@react-aria/i18n" "^3.12.4" + "@react-aria/interactions" "^3.22.5" + "@react-aria/label" "^3.7.13" + "@react-aria/spinbutton" "^3.6.10" + "@react-aria/utils" "^3.26.0" + "@react-stately/datepicker" "^3.11.0" + "@react-stately/form" "^3.1.0" + "@react-types/button" "^3.10.1" + "@react-types/calendar" "^3.5.0" + "@react-types/datepicker" "^3.9.0" + "@react-types/dialog" "^3.5.14" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" "@react-aria/dialog@^3.5.18": - version "3.5.19" - resolved "https://registry.yarnpkg.com/@react-aria/dialog/-/dialog-3.5.19.tgz#568b937e8f63078dabcccbc291ef0cef044aa2d0" - integrity sha512-I3AJWpAWCajj8Ama8qLQ18Tc37ODyk+Ym3haYEl5L4QnuFc0dU1sMJr15fppDGIxYjwvTTfctyhaSCz+S+wpkw== - dependencies: - "@react-aria/focus" "^3.18.4" - "@react-aria/overlays" "^3.23.4" - "@react-aria/utils" "^3.25.3" - "@react-types/dialog" "^3.5.13" - "@react-types/shared" "^3.25.0" + version "3.5.20" + resolved "https://registry.yarnpkg.com/@react-aria/dialog/-/dialog-3.5.20.tgz#6404d2c1bab1ea9ecce3ebc7adce64733ecea985" + integrity sha512-l0GZVLgeOd3kL3Yj8xQW7wN3gn9WW3RLd/SGI9t7ciTq+I/FhftjXCWzXLlOCCTLMf+gv7eazecECtmoWUaZWQ== + dependencies: + "@react-aria/focus" "^3.19.0" + "@react-aria/overlays" "^3.24.0" + "@react-aria/utils" "^3.26.0" + "@react-types/dialog" "^3.5.14" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" "@react-aria/dnd@^3.7.3": - version "3.7.4" - resolved "https://registry.yarnpkg.com/@react-aria/dnd/-/dnd-3.7.4.tgz#3e30f94569a39b381ebf353bb3d22e2a843fbd6f" - integrity sha512-lRE8SVyK/MPbF6NiVXHoriOV0QulNKkSndyDr3TWPsLhH5GKQso5jSx8/5ogbDgRTzIsmIQldj/HlW238DCiSg== - dependencies: - "@internationalized/string" "^3.2.4" - "@react-aria/i18n" "^3.12.3" - "@react-aria/interactions" "^3.22.4" - "@react-aria/live-announcer" "^3.4.0" - "@react-aria/overlays" "^3.23.4" - "@react-aria/utils" "^3.25.3" - "@react-stately/dnd" "^3.4.3" - "@react-types/button" "^3.10.0" - "@react-types/shared" "^3.25.0" + version "3.8.0" + resolved "https://registry.yarnpkg.com/@react-aria/dnd/-/dnd-3.8.0.tgz#7e3bfa3f509efeb9a872686e65641a719684e95a" + integrity sha512-JiqHY3E9fDU5Kb4gN22cuK6QNlpMCGe6ngR/BV+Q8mLEsdoWcoUAYOtYXVNNTRvCdVbEWI87FUU+ThyPpoDhNQ== + dependencies: + "@internationalized/string" "^3.2.5" + "@react-aria/i18n" "^3.12.4" + "@react-aria/interactions" "^3.22.5" + "@react-aria/live-announcer" "^3.4.1" + "@react-aria/overlays" "^3.24.0" + "@react-aria/utils" "^3.26.0" + "@react-stately/dnd" "^3.5.0" + "@react-types/button" "^3.10.1" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-aria/focus@^3.18.3", "@react-aria/focus@^3.18.4": - version "3.18.4" - resolved "https://registry.yarnpkg.com/@react-aria/focus/-/focus-3.18.4.tgz#a6e95896bc8680d1b5bcd855e983fc2c195a1a55" - integrity sha512-91J35077w9UNaMK1cpMUEFRkNNz0uZjnSwiyBCFuRdaVuivO53wNC9XtWSDNDdcO5cGy87vfJRVAiyoCn/mjqA== +"@react-aria/focus@^3.18.3", "@react-aria/focus@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@react-aria/focus/-/focus-3.19.0.tgz#82b9a5b83f023b943a7970df3d059f49d61df05d" + integrity sha512-hPF9EXoUQeQl1Y21/rbV2H4FdUR2v+4/I0/vB+8U3bT1CJ+1AFj1hc/rqx2DqEwDlEwOHN+E4+mRahQmlybq0A== dependencies: - "@react-aria/interactions" "^3.22.4" - "@react-aria/utils" "^3.25.3" - "@react-types/shared" "^3.25.0" + "@react-aria/interactions" "^3.22.5" + "@react-aria/utils" "^3.26.0" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" clsx "^2.0.0" -"@react-aria/form@^3.0.10": - version "3.0.10" - resolved "https://registry.yarnpkg.com/@react-aria/form/-/form-3.0.10.tgz#0d21bd33aac4153fcbfdd87cc04fce9f8e148650" - integrity sha512-hWBrqEXxBxcpYTJv0telQKaiu2728EUFHta8/RGBqJ4+MhKKxI7+PnLoms78IuiK0MCYvukHfun1fuQvK+8jsg== +"@react-aria/form@^3.0.11": + version "3.0.11" + resolved "https://registry.yarnpkg.com/@react-aria/form/-/form-3.0.11.tgz#84511874e1fad5f981bae97ebd4d549923849455" + integrity sha512-oXzjTiwVuuWjZ8muU0hp3BrDH5qjVctLOF50mjPvqUbvXQTHhoDxWweyIXPQjGshaqBd2w4pWaE4A2rG2O/apw== dependencies: - "@react-aria/interactions" "^3.22.4" - "@react-aria/utils" "^3.25.3" - "@react-stately/form" "^3.0.6" - "@react-types/shared" "^3.25.0" + "@react-aria/interactions" "^3.22.5" + "@react-aria/utils" "^3.26.0" + "@react-stately/form" "^3.1.0" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-aria/grid@^3.10.5": - version "3.10.5" - resolved "https://registry.yarnpkg.com/@react-aria/grid/-/grid-3.10.5.tgz#34caf94aa2442949e75a825684f6b7bea0b8af43" - integrity sha512-9sLa+rpLgRZk7VX+tvdSudn1tdVgolVzhDLGWd95yS4UtPVMihTMGBrRoByY57Wxvh1V+7Ptw8kc6tsRSotYKg== - dependencies: - "@react-aria/focus" "^3.18.4" - "@react-aria/i18n" "^3.12.3" - "@react-aria/interactions" "^3.22.4" - "@react-aria/live-announcer" "^3.4.0" - "@react-aria/selection" "^3.20.1" - "@react-aria/utils" "^3.25.3" - "@react-stately/collections" "^3.11.0" - "@react-stately/grid" "^3.9.3" - "@react-stately/selection" "^3.17.0" - "@react-types/checkbox" "^3.8.4" - "@react-types/grid" "^3.2.9" - "@react-types/shared" "^3.25.0" +"@react-aria/grid@^3.11.0": + version "3.11.0" + resolved "https://registry.yarnpkg.com/@react-aria/grid/-/grid-3.11.0.tgz#5ad6596745482e109b3b47f1fec7ce372f632707" + integrity sha512-lN5FpQgu2Rq0CzTPWmzRpq6QHcMmzsXYeClsgO3108uVp1/genBNAObYVTxGOKe/jb9q99trz8EtIn05O6KN1g== + dependencies: + "@react-aria/focus" "^3.19.0" + "@react-aria/i18n" "^3.12.4" + "@react-aria/interactions" "^3.22.5" + "@react-aria/live-announcer" "^3.4.1" + "@react-aria/selection" "^3.21.0" + "@react-aria/utils" "^3.26.0" + "@react-stately/collections" "^3.12.0" + "@react-stately/grid" "^3.10.0" + "@react-stately/selection" "^3.18.0" + "@react-types/checkbox" "^3.9.0" + "@react-types/grid" "^3.2.10" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-aria/gridlist@^3.9.4", "@react-aria/gridlist@^3.9.5": - version "3.9.5" - resolved "https://registry.yarnpkg.com/@react-aria/gridlist/-/gridlist-3.9.5.tgz#a1e6dbe7e14be9203630c76bfb73b55cd4d958c4" - integrity sha512-LM+3D0amZZ1qiyqWVG52j0YRWt2chdpx+WG80ryDKwHLDIq7uz1+KXyIfv8cFt/cZcl6+9Ft3kWALCAi6O4NLA== - dependencies: - "@react-aria/focus" "^3.18.4" - "@react-aria/grid" "^3.10.5" - "@react-aria/i18n" "^3.12.3" - "@react-aria/interactions" "^3.22.4" - "@react-aria/selection" "^3.20.1" - "@react-aria/utils" "^3.25.3" - "@react-stately/collections" "^3.11.0" - "@react-stately/list" "^3.11.0" - "@react-stately/tree" "^3.8.5" - "@react-types/shared" "^3.25.0" +"@react-aria/gridlist@^3.10.0", "@react-aria/gridlist@^3.9.4": + version "3.10.0" + resolved "https://registry.yarnpkg.com/@react-aria/gridlist/-/gridlist-3.10.0.tgz#adc2f9896a2759bb29cec428378c8ac85235a110" + integrity sha512-UcblfSZ7kJBrjg9mQ5VbnRevN81UiYB4NuL5PwIpBpridO7tnl4ew6+96PYU7Wj1chHhPS3x0b0zmuSVN7A0LA== + dependencies: + "@react-aria/focus" "^3.19.0" + "@react-aria/grid" "^3.11.0" + "@react-aria/i18n" "^3.12.4" + "@react-aria/interactions" "^3.22.5" + "@react-aria/selection" "^3.21.0" + "@react-aria/utils" "^3.26.0" + "@react-stately/collections" "^3.12.0" + "@react-stately/list" "^3.11.1" + "@react-stately/tree" "^3.8.6" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-aria/i18n@^3.12.3": - version "3.12.3" - resolved "https://registry.yarnpkg.com/@react-aria/i18n/-/i18n-3.12.3.tgz#ec902787ea840755a1e7b4feb64435b8451baf62" - integrity sha512-0Tp/4JwnCVNKDfuknPF+/xf3/woOc8gUjTU2nCjO3mCVb4FU7KFtjxQ2rrx+6hpIVG6g+N9qfMjRa/ggVH0CJg== - dependencies: - "@internationalized/date" "^3.5.6" - "@internationalized/message" "^3.1.5" - "@internationalized/number" "^3.5.4" - "@internationalized/string" "^3.2.4" - "@react-aria/ssr" "^3.9.6" - "@react-aria/utils" "^3.25.3" - "@react-types/shared" "^3.25.0" +"@react-aria/i18n@^3.12.3", "@react-aria/i18n@^3.12.4": + version "3.12.4" + resolved "https://registry.yarnpkg.com/@react-aria/i18n/-/i18n-3.12.4.tgz#4520ce48a1b6ebe4aa470d72eba300e65de01814" + integrity sha512-j9+UL3q0Ls8MhXV9gtnKlyozq4aM95YywXqnmJtzT1rYeBx7w28hooqrWkCYLfqr4OIryv1KUnPiCSLwC2OC7w== + dependencies: + "@internationalized/date" "^3.6.0" + "@internationalized/message" "^3.1.6" + "@internationalized/number" "^3.6.0" + "@internationalized/string" "^3.2.5" + "@react-aria/ssr" "^3.9.7" + "@react-aria/utils" "^3.26.0" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-aria/interactions@^3.22.3", "@react-aria/interactions@^3.22.4": - version "3.22.4" - resolved "https://registry.yarnpkg.com/@react-aria/interactions/-/interactions-3.22.4.tgz#88ed61ab6a485f869bc1f65ae6688d48ca96064b" - integrity sha512-E0vsgtpItmknq/MJELqYJwib+YN18Qag8nroqwjk1qOnBa9ROIkUhWJerLi1qs5diXq9LHKehZDXRlwPvdEFww== +"@react-aria/interactions@^3.22.3", "@react-aria/interactions@^3.22.5": + version "3.22.5" + resolved "https://registry.yarnpkg.com/@react-aria/interactions/-/interactions-3.22.5.tgz#9cd8c93b8b6988f1d315d3efb450119d1432bbb8" + integrity sha512-kMwiAD9E0TQp+XNnOs13yVJghiy8ET8L0cbkeuTgNI96sOAp/63EJ1FSrDf17iD8sdjt41LafwX/dKXW9nCcLQ== dependencies: - "@react-aria/ssr" "^3.9.6" - "@react-aria/utils" "^3.25.3" - "@react-types/shared" "^3.25.0" + "@react-aria/ssr" "^3.9.7" + "@react-aria/utils" "^3.26.0" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-aria/label@^3.7.12": - version "3.7.12" - resolved "https://registry.yarnpkg.com/@react-aria/label/-/label-3.7.12.tgz#d6aa0dca5d0ba280fd6f15c1f05327095a2526c5" - integrity sha512-u9xT90lAlgb7xiv+p0md9QwCHz65XL7tjS5e29e88Rs3ptkv3aQubTqxVOUTEwzbNUT4A1QqTjUm1yfHewIRUw== +"@react-aria/label@^3.7.12", "@react-aria/label@^3.7.13": + version "3.7.13" + resolved "https://registry.yarnpkg.com/@react-aria/label/-/label-3.7.13.tgz#9e7153a1ded878b5147d141effc3eb226f3c6c1f" + integrity sha512-brSAXZVTey5RG/Ex6mTrV/9IhGSQFU4Al34qmjEDho+Z2qT4oPwf8k7TRXWWqzOU0ugYxekYbsLd2zlN3XvWcg== dependencies: - "@react-aria/utils" "^3.25.3" - "@react-types/shared" "^3.25.0" + "@react-aria/utils" "^3.26.0" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-aria/link@^3.7.5", "@react-aria/link@^3.7.6": - version "3.7.6" - resolved "https://registry.yarnpkg.com/@react-aria/link/-/link-3.7.6.tgz#d71e9f1c16b671f017b69f078887432ffc65ac65" - integrity sha512-8buJznRWoOud8ApygUAz7TsshXNs6HDGB6YOYEJxy0WTKILn0U5NUymw2PWC14+bWRPelHMKmi6vbFBrJWzSzQ== +"@react-aria/link@^3.7.5", "@react-aria/link@^3.7.7": + version "3.7.7" + resolved "https://registry.yarnpkg.com/@react-aria/link/-/link-3.7.7.tgz#5879c75068b63d55353b3e96b4fda0fa8753d1ad" + integrity sha512-eVBRcHKhNSsATYWv5wRnZXRqPVcKAWWakyvfrYePIKpC3s4BaHZyTGYdefk8ZwZdEOuQZBqLMnjW80q1uhtkuA== dependencies: - "@react-aria/focus" "^3.18.4" - "@react-aria/interactions" "^3.22.4" - "@react-aria/utils" "^3.25.3" - "@react-types/link" "^3.5.8" - "@react-types/shared" "^3.25.0" + "@react-aria/focus" "^3.19.0" + "@react-aria/interactions" "^3.22.5" + "@react-aria/utils" "^3.26.0" + "@react-types/link" "^3.5.9" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-aria/listbox@^3.13.4", "@react-aria/listbox@^3.13.5": - version "3.13.5" - resolved "https://registry.yarnpkg.com/@react-aria/listbox/-/listbox-3.13.5.tgz#67b628c5fc9c5dbee327a012ae82d05ebc60b75d" - integrity sha512-tn32L/PIELIPYfDWCJ3OBRvvb/jCEvIzs6IYs8xCISV5W4853Je/WnA8wumWnz07U9sODYFmHUx2ThO7Z7dH7Q== - dependencies: - "@react-aria/interactions" "^3.22.4" - "@react-aria/label" "^3.7.12" - "@react-aria/selection" "^3.20.1" - "@react-aria/utils" "^3.25.3" - "@react-stately/collections" "^3.11.0" - "@react-stately/list" "^3.11.0" - "@react-types/listbox" "^3.5.2" - "@react-types/shared" "^3.25.0" +"@react-aria/listbox@^3.13.4", "@react-aria/listbox@^3.13.6": + version "3.13.6" + resolved "https://registry.yarnpkg.com/@react-aria/listbox/-/listbox-3.13.6.tgz#43ff24f4a6540a9952729833201460fa6ab081f7" + integrity sha512-6hEXEXIZVau9lgBZ4VVjFR3JnGU+fJaPmV3HP0UZ2ucUptfG0MZo24cn+ZQJsWiuaCfNFv5b8qribiv+BcO+Kg== + dependencies: + "@react-aria/interactions" "^3.22.5" + "@react-aria/label" "^3.7.13" + "@react-aria/selection" "^3.21.0" + "@react-aria/utils" "^3.26.0" + "@react-stately/collections" "^3.12.0" + "@react-stately/list" "^3.11.1" + "@react-types/listbox" "^3.5.3" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-aria/live-announcer@^3.4.0": - version "3.4.0" - resolved "https://registry.yarnpkg.com/@react-aria/live-announcer/-/live-announcer-3.4.0.tgz#0ad90fddc4731e93071d802c8cec9e1dfd2fc448" - integrity sha512-VBxEdMq2SbtRbNTQNcDR2G6E3lEl5cJSBiHTTO8Ln1AL76LiazrylIXGgoktqzCfRQmyq0v8CHk1cNKDU9mvJg== +"@react-aria/live-announcer@^3.4.1": + version "3.4.1" + resolved "https://registry.yarnpkg.com/@react-aria/live-announcer/-/live-announcer-3.4.1.tgz#efedf706b23f6e1b526a3a35c14c202ac3e68487" + integrity sha512-4X2mcxgqLvvkqxv2l1n00jTzUxxe0kkLiapBGH1LHX/CxA1oQcHDqv8etJ2ZOwmS/MSBBiWnv3DwYHDOF6ubig== dependencies: "@swc/helpers" "^0.5.0" -"@react-aria/menu@^3.15.4", "@react-aria/menu@^3.15.5": - version "3.15.5" - resolved "https://registry.yarnpkg.com/@react-aria/menu/-/menu-3.15.5.tgz#b133a0d60da94dfbbd1bfe3db485cf91ccfff900" - integrity sha512-ygfS032hJSZCYYbMHnUSmUTVMaz99L9AUZ9kMa6g+k2X1t92K1gXfhYYkoClQD6+G0ch7zm0SwYFlUmRf9yOEA== - dependencies: - "@react-aria/focus" "^3.18.4" - "@react-aria/i18n" "^3.12.3" - "@react-aria/interactions" "^3.22.4" - "@react-aria/overlays" "^3.23.4" - "@react-aria/selection" "^3.20.1" - "@react-aria/utils" "^3.25.3" - "@react-stately/collections" "^3.11.0" - "@react-stately/menu" "^3.8.3" - "@react-stately/tree" "^3.8.5" - "@react-types/button" "^3.10.0" - "@react-types/menu" "^3.9.12" - "@react-types/shared" "^3.25.0" +"@react-aria/menu@^3.15.4", "@react-aria/menu@^3.16.0": + version "3.16.0" + resolved "https://registry.yarnpkg.com/@react-aria/menu/-/menu-3.16.0.tgz#119e562806e9f8a39fd468ab790d788905c6df83" + integrity sha512-TNk+Vd3TbpBPUxEloAdHRTaRxf9JBK7YmkHYiq0Yj5Lc22KS0E2eTyhpPM9xJvEWN2TlC5TEvNfdyui2kYWFFQ== + dependencies: + "@react-aria/focus" "^3.19.0" + "@react-aria/i18n" "^3.12.4" + "@react-aria/interactions" "^3.22.5" + "@react-aria/overlays" "^3.24.0" + "@react-aria/selection" "^3.21.0" + "@react-aria/utils" "^3.26.0" + "@react-stately/collections" "^3.12.0" + "@react-stately/menu" "^3.9.0" + "@react-stately/selection" "^3.18.0" + "@react-stately/tree" "^3.8.6" + "@react-types/button" "^3.10.1" + "@react-types/menu" "^3.9.13" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" "@react-aria/meter@^3.4.17": - version "3.4.17" - resolved "https://registry.yarnpkg.com/@react-aria/meter/-/meter-3.4.17.tgz#ace0323e9d74c1967b4a700db744161aff366084" - integrity sha512-08wbQhfvVWzpWilhn/WD7cQ7TqafS/66umTk7+X6BW6TrS1//6loNNJV62IC3F7sskel4iEAtl2gW0WpW8zEdg== + version "3.4.18" + resolved "https://registry.yarnpkg.com/@react-aria/meter/-/meter-3.4.18.tgz#ff3f85f32ea30285e7e73386a641efdcedd88205" + integrity sha512-tTX3LLlmDIHqrC42dkdf+upb1c4UbhlpZ52gqB64lZD4OD4HE+vMTwNSe+7MRKMLvcdKPWCRC35PnxIHZ15kfQ== dependencies: - "@react-aria/progress" "^3.4.17" - "@react-types/meter" "^3.4.4" - "@react-types/shared" "^3.25.0" + "@react-aria/progress" "^3.4.18" + "@react-types/meter" "^3.4.5" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-aria/numberfield@^3.11.7", "@react-aria/numberfield@^3.11.8": - version "3.11.8" - resolved "https://registry.yarnpkg.com/@react-aria/numberfield/-/numberfield-3.11.8.tgz#d1682305df3cc64ce3a66f9ee997eb778a1aa077" - integrity sha512-CWRHbrjfpvEqBmtjwX8LjVds6+tMNneRlKF46ked5sZilfU2jIirufaucM36N4vX6N/W7nFR/rCbp2WCOU9p3Q== - dependencies: - "@react-aria/i18n" "^3.12.3" - "@react-aria/interactions" "^3.22.4" - "@react-aria/spinbutton" "^3.6.9" - "@react-aria/textfield" "^3.14.10" - "@react-aria/utils" "^3.25.3" - "@react-stately/form" "^3.0.6" - "@react-stately/numberfield" "^3.9.7" - "@react-types/button" "^3.10.0" - "@react-types/numberfield" "^3.8.6" - "@react-types/shared" "^3.25.0" +"@react-aria/numberfield@^3.11.7", "@react-aria/numberfield@^3.11.9": + version "3.11.9" + resolved "https://registry.yarnpkg.com/@react-aria/numberfield/-/numberfield-3.11.9.tgz#175f801b18740534dca023cfd9ce0349eff940b0" + integrity sha512-3tiGPx2y4zyOV7PmdBASes99ZZsFTZAJTnU45Z+p1CW4131lw7y2ZhbojBl7U6DaXAJvi1z6zY6cq2UE9w5a0Q== + dependencies: + "@react-aria/i18n" "^3.12.4" + "@react-aria/interactions" "^3.22.5" + "@react-aria/spinbutton" "^3.6.10" + "@react-aria/textfield" "^3.15.0" + "@react-aria/utils" "^3.26.0" + "@react-stately/form" "^3.1.0" + "@react-stately/numberfield" "^3.9.8" + "@react-types/button" "^3.10.1" + "@react-types/numberfield" "^3.8.7" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-aria/overlays@^3.23.3", "@react-aria/overlays@^3.23.4": - version "3.23.4" - resolved "https://registry.yarnpkg.com/@react-aria/overlays/-/overlays-3.23.4.tgz#8fc2f7f5884f514056651490a17b9fd40e519df1" - integrity sha512-MZUW6SUlTWOwKuFTqUTxW5BnvdW3Y9cEwanWuz98NX3ST7JYe/3ZcZhb37/fGW4uoGHnQ9icEwVf0rbMrK2STg== - dependencies: - "@react-aria/focus" "^3.18.4" - "@react-aria/i18n" "^3.12.3" - "@react-aria/interactions" "^3.22.4" - "@react-aria/ssr" "^3.9.6" - "@react-aria/utils" "^3.25.3" - "@react-aria/visually-hidden" "^3.8.17" - "@react-stately/overlays" "^3.6.11" - "@react-types/button" "^3.10.0" - "@react-types/overlays" "^3.8.10" - "@react-types/shared" "^3.25.0" +"@react-aria/overlays@^3.23.3", "@react-aria/overlays@^3.24.0": + version "3.24.0" + resolved "https://registry.yarnpkg.com/@react-aria/overlays/-/overlays-3.24.0.tgz#7f97cd12506961abfab3ae653822cea05d1cacd3" + integrity sha512-0kAXBsMNTc/a3M07tK9Cdt/ea8CxTAEJ223g8YgqImlmoBBYAL7dl5G01IOj67TM64uWPTmZrOklBchHWgEm3A== + dependencies: + "@react-aria/focus" "^3.19.0" + "@react-aria/i18n" "^3.12.4" + "@react-aria/interactions" "^3.22.5" + "@react-aria/ssr" "^3.9.7" + "@react-aria/utils" "^3.26.0" + "@react-aria/visually-hidden" "^3.8.18" + "@react-stately/overlays" "^3.6.12" + "@react-types/button" "^3.10.1" + "@react-types/overlays" "^3.8.11" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-aria/progress@^3.4.17": - version "3.4.17" - resolved "https://registry.yarnpkg.com/@react-aria/progress/-/progress-3.4.17.tgz#19b7ce3577049af679fba415e2ba177c68c3a125" - integrity sha512-5+01WNibLoNS5KcfU5p6vg7Lhz17plqqzv/uITx28zzj3saaj0VLR7n57Ig2fXe8ZEQoUS89BS3sIEsIf96S1A== +"@react-aria/progress@^3.4.17", "@react-aria/progress@^3.4.18": + version "3.4.18" + resolved "https://registry.yarnpkg.com/@react-aria/progress/-/progress-3.4.18.tgz#948859ce1b0e13d935da7d4cbe6812d451472fe4" + integrity sha512-FOLgJ9t9i1u3oAAimybJG6r7/soNPBnJfWo4Yr6MmaUv90qVGa1h6kiuM5m9H/bm5JobAebhdfHit9lFlgsCmg== dependencies: - "@react-aria/i18n" "^3.12.3" - "@react-aria/label" "^3.7.12" - "@react-aria/utils" "^3.25.3" - "@react-types/progress" "^3.5.7" - "@react-types/shared" "^3.25.0" + "@react-aria/i18n" "^3.12.4" + "@react-aria/label" "^3.7.13" + "@react-aria/utils" "^3.26.0" + "@react-types/progress" "^3.5.8" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" "@react-aria/radio@^3.10.8": - version "3.10.9" - resolved "https://registry.yarnpkg.com/@react-aria/radio/-/radio-3.10.9.tgz#bca231f4f6136b6272bf1ee7701c22180553af4f" - integrity sha512-XnU7zGTEku1mPvJweX4I3ifwEBtglEWYoO4CZGvA3eXj39X8iGwNZXUst1pdk2ykWUKbtwrmsWA6zG2OAGODYw== - dependencies: - "@react-aria/focus" "^3.18.4" - "@react-aria/form" "^3.0.10" - "@react-aria/i18n" "^3.12.3" - "@react-aria/interactions" "^3.22.4" - "@react-aria/label" "^3.7.12" - "@react-aria/utils" "^3.25.3" - "@react-stately/radio" "^3.10.8" - "@react-types/radio" "^3.8.4" - "@react-types/shared" "^3.25.0" + version "3.10.10" + resolved "https://registry.yarnpkg.com/@react-aria/radio/-/radio-3.10.10.tgz#18e2811fb3e72298414c880bd9405ea3f1d83f1f" + integrity sha512-NVdeOVrsrHgSfwL2jWCCXFsWZb+RMRZErj5vthHQW4nkHECGOzeX56VaLWTSvdoCPqi9wdIX8A6K9peeAIgxzA== + dependencies: + "@react-aria/focus" "^3.19.0" + "@react-aria/form" "^3.0.11" + "@react-aria/i18n" "^3.12.4" + "@react-aria/interactions" "^3.22.5" + "@react-aria/label" "^3.7.13" + "@react-aria/utils" "^3.26.0" + "@react-stately/radio" "^3.10.9" + "@react-types/radio" "^3.8.5" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" "@react-aria/searchfield@^3.7.9": - version "3.7.10" - resolved "https://registry.yarnpkg.com/@react-aria/searchfield/-/searchfield-3.7.10.tgz#a8997321e0e6aa8df8f36b39f4ab927eb744aaf0" - integrity sha512-1XTYh2dycedaK1tgpHAHcu8PTK1wG3dv53yLziu07JsBe9tX6O8jIFBhZK8SpfNnP8pEOI3PIlVEjaarLwgWzQ== - dependencies: - "@react-aria/i18n" "^3.12.3" - "@react-aria/textfield" "^3.14.10" - "@react-aria/utils" "^3.25.3" - "@react-stately/searchfield" "^3.5.7" - "@react-types/button" "^3.10.0" - "@react-types/searchfield" "^3.5.9" - "@react-types/shared" "^3.25.0" + version "3.7.11" + resolved "https://registry.yarnpkg.com/@react-aria/searchfield/-/searchfield-3.7.11.tgz#2be234280cc4fb58a316db6ba1f95ea34754c043" + integrity sha512-wFf6QxtBFfoxy0ANxI0+ftFEBGynVCY0+ce4H4Y9LpUTQsIKMp3sdc7LoUFORWw5Yee6Eid5cFPQX0Ymnk+ZJg== + dependencies: + "@react-aria/i18n" "^3.12.4" + "@react-aria/textfield" "^3.15.0" + "@react-aria/utils" "^3.26.0" + "@react-stately/searchfield" "^3.5.8" + "@react-types/button" "^3.10.1" + "@react-types/searchfield" "^3.5.10" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" "@react-aria/select@^3.14.10": - version "3.14.11" - resolved "https://registry.yarnpkg.com/@react-aria/select/-/select-3.14.11.tgz#705d51c7b39bedcb1dfb0f59280f2aa4ae747584" - integrity sha512-rX5U4JcPNV41lNEF1tAxNxqrGENnLGZL/D5Y+YNpqKSU5U09+hD3ovsflNkF/d+deb25zg45JRxumwOCQ+rfyw== - dependencies: - "@react-aria/form" "^3.0.10" - "@react-aria/i18n" "^3.12.3" - "@react-aria/interactions" "^3.22.4" - "@react-aria/label" "^3.7.12" - "@react-aria/listbox" "^3.13.5" - "@react-aria/menu" "^3.15.5" - "@react-aria/selection" "^3.20.1" - "@react-aria/utils" "^3.25.3" - "@react-aria/visually-hidden" "^3.8.17" - "@react-stately/select" "^3.6.8" - "@react-types/button" "^3.10.0" - "@react-types/select" "^3.9.7" - "@react-types/shared" "^3.25.0" + version "3.15.0" + resolved "https://registry.yarnpkg.com/@react-aria/select/-/select-3.15.0.tgz#e0b955ed908039f734805e852b58dec4b159adc9" + integrity sha512-zgBOUNy81aJplfc3NKDJMv8HkXjBGzaFF3XDzNfW8vJ7nD9rcTRUN5SQ1XCEnKMv12B/Euk9zt6kd+tX0wk1vQ== + dependencies: + "@react-aria/form" "^3.0.11" + "@react-aria/i18n" "^3.12.4" + "@react-aria/interactions" "^3.22.5" + "@react-aria/label" "^3.7.13" + "@react-aria/listbox" "^3.13.6" + "@react-aria/menu" "^3.16.0" + "@react-aria/selection" "^3.21.0" + "@react-aria/utils" "^3.26.0" + "@react-aria/visually-hidden" "^3.8.18" + "@react-stately/select" "^3.6.9" + "@react-types/button" "^3.10.1" + "@react-types/select" "^3.9.8" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-aria/selection@^3.20.0", "@react-aria/selection@^3.20.1": - version "3.20.1" - resolved "https://registry.yarnpkg.com/@react-aria/selection/-/selection-3.20.1.tgz#94b405214ea8506410f632fd2bfe470b9360ebfb" - integrity sha512-My0w8UC/7PAkz/1yZUjr2VRuzDZz1RrbgTqP36j5hsJx8RczDTjI4TmKtQNKG0ggaP4w83G2Og5JPTq3w3LMAw== - dependencies: - "@react-aria/focus" "^3.18.4" - "@react-aria/i18n" "^3.12.3" - "@react-aria/interactions" "^3.22.4" - "@react-aria/utils" "^3.25.3" - "@react-stately/selection" "^3.17.0" - "@react-types/shared" "^3.25.0" +"@react-aria/selection@^3.20.0", "@react-aria/selection@^3.21.0": + version "3.21.0" + resolved "https://registry.yarnpkg.com/@react-aria/selection/-/selection-3.21.0.tgz#c5660e73a38db5e3e1cdc722e408b4489f5f589a" + integrity sha512-52JJ6hlPcM+gt0VV3DBmz6Kj1YAJr13TfutrKfGWcK36LvNCBm1j0N+TDqbdnlp8Nue6w0+5FIwZq44XPYiBGg== + dependencies: + "@react-aria/focus" "^3.19.0" + "@react-aria/i18n" "^3.12.4" + "@react-aria/interactions" "^3.22.5" + "@react-aria/utils" "^3.26.0" + "@react-stately/selection" "^3.18.0" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" "@react-aria/separator@^3.4.3": - version "3.4.3" - resolved "https://registry.yarnpkg.com/@react-aria/separator/-/separator-3.4.3.tgz#c13b06d185ecea3e69260428b0cbdee4ae7e8f18" - integrity sha512-L+eCmSGfRJ9jScHZqBkmOkp44LBARisDjRdYbGrLlsAEcOiHUXufnfpxz2rgkUGBdUgnI9hIk12q5kdy0UxGjg== + version "3.4.4" + resolved "https://registry.yarnpkg.com/@react-aria/separator/-/separator-3.4.4.tgz#7975177d256d8e864625d9823bf7a6de5a6b6460" + integrity sha512-dH+qt0Mdh0nhKXCHW6AR4DF8DKLUBP26QYWaoThPdBwIpypH/JVKowpPtWms1P4b36U6XzHXHnTTEn/ZVoCqNA== dependencies: - "@react-aria/utils" "^3.25.3" - "@react-types/shared" "^3.25.0" + "@react-aria/utils" "^3.26.0" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-aria/slider@^3.7.12", "@react-aria/slider@^3.7.13": - version "3.7.13" - resolved "https://registry.yarnpkg.com/@react-aria/slider/-/slider-3.7.13.tgz#ddd0e08faf5c16cb90176d4bf8663cd7d1d43bce" - integrity sha512-yGlIpoOUKUoP0M3iI8ZHU001NASBOeZJSIQNfoS7HiqSR3bz+6BX7DRAM6B+CPHJleUtrdQ6JjO/8V8ZUV2kNQ== - dependencies: - "@react-aria/focus" "^3.18.4" - "@react-aria/i18n" "^3.12.3" - "@react-aria/interactions" "^3.22.4" - "@react-aria/label" "^3.7.12" - "@react-aria/utils" "^3.25.3" - "@react-stately/slider" "^3.5.8" - "@react-types/shared" "^3.25.0" - "@react-types/slider" "^3.7.6" +"@react-aria/slider@^3.7.12", "@react-aria/slider@^3.7.14": + version "3.7.14" + resolved "https://registry.yarnpkg.com/@react-aria/slider/-/slider-3.7.14.tgz#25a362725d6cd71e9b86477362a36c847c73384e" + integrity sha512-7rOiKjLkEZ0j7mPMlwrqivc+K4OSfL14slaQp06GHRiJkhiWXh2/drPe15hgNq55HmBQBpA0umKMkJcqVgmXPA== + dependencies: + "@react-aria/focus" "^3.19.0" + "@react-aria/i18n" "^3.12.4" + "@react-aria/interactions" "^3.22.5" + "@react-aria/label" "^3.7.13" + "@react-aria/utils" "^3.26.0" + "@react-stately/slider" "^3.6.0" + "@react-types/shared" "^3.26.0" + "@react-types/slider" "^3.7.7" "@swc/helpers" "^0.5.0" -"@react-aria/spinbutton@^3.6.9": - version "3.6.9" - resolved "https://registry.yarnpkg.com/@react-aria/spinbutton/-/spinbutton-3.6.9.tgz#9a74c0ec927d0a7949463efcddb5c52fc9841fa8" - integrity sha512-m+uVJdiIc2LrLVDGjU7p8P2O2gUvTN26GR+NgH4rl+tUSuAB0+T1rjls/C+oXEqQjCpQihEB9Bt4M+VHpzmyjA== - dependencies: - "@react-aria/i18n" "^3.12.3" - "@react-aria/live-announcer" "^3.4.0" - "@react-aria/utils" "^3.25.3" - "@react-types/button" "^3.10.0" - "@react-types/shared" "^3.25.0" +"@react-aria/spinbutton@^3.6.10": + version "3.6.10" + resolved "https://registry.yarnpkg.com/@react-aria/spinbutton/-/spinbutton-3.6.10.tgz#72154873de807638e17570bd57e8491912b613b7" + integrity sha512-nhYEYk7xUNOZDaqiQ5w/nHH9ouqjJbabTWXH+KK7UR1oVGfo4z1wG94l8KWF3Z6SGGnBxzLJyTBguZ4g9aYTSg== + dependencies: + "@react-aria/i18n" "^3.12.4" + "@react-aria/live-announcer" "^3.4.1" + "@react-aria/utils" "^3.26.0" + "@react-types/button" "^3.10.1" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-aria/ssr@^3.9.6": - version "3.9.6" - resolved "https://registry.yarnpkg.com/@react-aria/ssr/-/ssr-3.9.6.tgz#a9e8b351acdc8238f2b5215b0ce904636c6ea690" - integrity sha512-iLo82l82ilMiVGy342SELjshuWottlb5+VefO3jOQqQRNYnJBFpUSadswDPbRimSgJUZuFwIEYs6AabkP038fA== +"@react-aria/ssr@^3.9.6", "@react-aria/ssr@^3.9.7": + version "3.9.7" + resolved "https://registry.yarnpkg.com/@react-aria/ssr/-/ssr-3.9.7.tgz#d89d129f7bbc5148657e6c952ac31c9353183770" + integrity sha512-GQygZaGlmYjmYM+tiNBA5C6acmiDWF52Nqd40bBp0Znk4M4hP+LTmI0lpI1BuKMw45T8RIhrAsICIfKwZvi2Gg== dependencies: "@swc/helpers" "^0.5.0" "@react-aria/switch@^3.6.8": - version "3.6.9" - resolved "https://registry.yarnpkg.com/@react-aria/switch/-/switch-3.6.9.tgz#66a299fccb8efdfb474c9ed4a99b124d7511572c" - integrity sha512-w7xIywpR6llm22DXYOObZ2Uqvsw+gNmxdJ86h8+YRtpSkFnPMhXtTMv3RXpEGYhPTt/YDIqfxiluF1E2IHGwIA== + version "3.6.10" + resolved "https://registry.yarnpkg.com/@react-aria/switch/-/switch-3.6.10.tgz#8fa5729bc4e76ac3df51389a8996873142daedb8" + integrity sha512-FtaI9WaEP1tAmra1sYlAkYXg9x75P5UtgY8pSbe9+1WRyWbuE1QZT+RNCTi3IU4fZ7iJQmXH6+VaMyzPlSUagw== dependencies: - "@react-aria/toggle" "^3.10.9" - "@react-stately/toggle" "^3.7.8" - "@react-types/shared" "^3.25.0" - "@react-types/switch" "^3.5.6" + "@react-aria/toggle" "^3.10.10" + "@react-stately/toggle" "^3.8.0" + "@react-types/shared" "^3.26.0" + "@react-types/switch" "^3.5.7" "@swc/helpers" "^0.5.0" "@react-aria/table@^3.15.4": - version "3.15.5" - resolved "https://registry.yarnpkg.com/@react-aria/table/-/table-3.15.5.tgz#241a93e2c8c1dd55b77676a2d19bb86ea6ff814a" - integrity sha512-bdNZF0ZoNOfyOEIK/ctv0llacaCNk8mv+GGy8mwh5bZeJjd8KuDIpYQtZJYvf2YVvPYRWyXRhF0/B229m65f/g== - dependencies: - "@react-aria/focus" "^3.18.4" - "@react-aria/grid" "^3.10.5" - "@react-aria/i18n" "^3.12.3" - "@react-aria/interactions" "^3.22.4" - "@react-aria/live-announcer" "^3.4.0" - "@react-aria/utils" "^3.25.3" - "@react-aria/visually-hidden" "^3.8.17" - "@react-stately/collections" "^3.11.0" - "@react-stately/flags" "^3.0.4" - "@react-stately/table" "^3.12.3" - "@react-types/checkbox" "^3.8.4" - "@react-types/grid" "^3.2.9" - "@react-types/shared" "^3.25.0" - "@react-types/table" "^3.10.2" + version "3.16.0" + resolved "https://registry.yarnpkg.com/@react-aria/table/-/table-3.16.0.tgz#f0ffb51f52494e68f2c3b81fba44278fbdc48c28" + integrity sha512-9xF9S3CJ7XRiiK92hsIKxPedD0kgcQWwqTMtj3IBynpQ4vsnRiW3YNIzrn9C3apjknRZDTSta8O2QPYCUMmw2A== + dependencies: + "@react-aria/focus" "^3.19.0" + "@react-aria/grid" "^3.11.0" + "@react-aria/i18n" "^3.12.4" + "@react-aria/interactions" "^3.22.5" + "@react-aria/live-announcer" "^3.4.1" + "@react-aria/utils" "^3.26.0" + "@react-aria/visually-hidden" "^3.8.18" + "@react-stately/collections" "^3.12.0" + "@react-stately/flags" "^3.0.5" + "@react-stately/table" "^3.13.0" + "@react-types/checkbox" "^3.9.0" + "@react-types/grid" "^3.2.10" + "@react-types/shared" "^3.26.0" + "@react-types/table" "^3.10.3" "@swc/helpers" "^0.5.0" "@react-aria/tabs@^3.9.6": - version "3.9.7" - resolved "https://registry.yarnpkg.com/@react-aria/tabs/-/tabs-3.9.7.tgz#2e44203e51f8b953cf3cc2dc2867b27cafb40a33" - integrity sha512-f78P2Y9ZCYtwOnteku9mPVIk21xSSREYWaQPtA9ebSgVbeR5ya6RpaX9ISc9cd0HEF3Av+hZYyS1pNXXWymv9g== - dependencies: - "@react-aria/focus" "^3.18.4" - "@react-aria/i18n" "^3.12.3" - "@react-aria/selection" "^3.20.1" - "@react-aria/utils" "^3.25.3" - "@react-stately/tabs" "^3.6.10" - "@react-types/shared" "^3.25.0" - "@react-types/tabs" "^3.3.10" + version "3.9.8" + resolved "https://registry.yarnpkg.com/@react-aria/tabs/-/tabs-3.9.8.tgz#a0a647a4e2d1783125779473536419fd8caa9cfa" + integrity sha512-Nur/qRFBe+Zrt4xcCJV/ULXCS3Mlae+B89bp1Gl20vSDqk6uaPtGk+cS5k03eugOvas7AQapqNJsJgKd66TChw== + dependencies: + "@react-aria/focus" "^3.19.0" + "@react-aria/i18n" "^3.12.4" + "@react-aria/selection" "^3.21.0" + "@react-aria/utils" "^3.26.0" + "@react-stately/tabs" "^3.7.0" + "@react-types/shared" "^3.26.0" + "@react-types/tabs" "^3.3.11" "@swc/helpers" "^0.5.0" "@react-aria/tag@^3.4.6": - version "3.4.7" - resolved "https://registry.yarnpkg.com/@react-aria/tag/-/tag-3.4.7.tgz#1b3e527cc9d7d948c67514cde64d82b7c2276e7f" - integrity sha512-hreVvphUeYUfMN6gjM3+WouN2P/WGuR0rGpOrFk2HEnGDPg3Ar0isfdAaciTSBOc26CDKNgrmzRguxCmKKuqgw== - dependencies: - "@react-aria/gridlist" "^3.9.5" - "@react-aria/i18n" "^3.12.3" - "@react-aria/interactions" "^3.22.4" - "@react-aria/label" "^3.7.12" - "@react-aria/selection" "^3.20.1" - "@react-aria/utils" "^3.25.3" - "@react-stately/list" "^3.11.0" - "@react-types/button" "^3.10.0" - "@react-types/shared" "^3.25.0" + version "3.4.8" + resolved "https://registry.yarnpkg.com/@react-aria/tag/-/tag-3.4.8.tgz#856899a53c2be2b8aea3d5aca020edf8608246b2" + integrity sha512-exWl52bsFtJuzaqMYvSnLteUoPqb3Wf+uICru/yRtREJsWVqjJF38NCVlU73Yqd9qMPTctDrboSZFAWAWKDxoA== + dependencies: + "@react-aria/gridlist" "^3.10.0" + "@react-aria/i18n" "^3.12.4" + "@react-aria/interactions" "^3.22.5" + "@react-aria/label" "^3.7.13" + "@react-aria/selection" "^3.21.0" + "@react-aria/utils" "^3.26.0" + "@react-stately/list" "^3.11.1" + "@react-types/button" "^3.10.1" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-aria/textfield@^3.14.10", "@react-aria/textfield@^3.14.9": - version "3.14.10" - resolved "https://registry.yarnpkg.com/@react-aria/textfield/-/textfield-3.14.10.tgz#a6fab9993f26f97b27c5bba1a23d757d09c43d62" - integrity sha512-vG44FgxwfJUF2S6tRG+Sg646DDEgs0CO9RYniafEOHz8rwcNIH3lML7n8LAfzQa+BjBY28+UF0wmqEvd6VCzCQ== - dependencies: - "@react-aria/focus" "^3.18.4" - "@react-aria/form" "^3.0.10" - "@react-aria/label" "^3.7.12" - "@react-aria/utils" "^3.25.3" - "@react-stately/form" "^3.0.6" - "@react-stately/utils" "^3.10.4" - "@react-types/shared" "^3.25.0" - "@react-types/textfield" "^3.9.7" +"@react-aria/textfield@^3.14.9", "@react-aria/textfield@^3.15.0": + version "3.15.0" + resolved "https://registry.yarnpkg.com/@react-aria/textfield/-/textfield-3.15.0.tgz#17ebac0b73f084622aaf9697576b82155bed67cb" + integrity sha512-V5mg7y1OR6WXYHdhhm4FC7QyGc9TideVRDFij1SdOJrIo5IFB7lvwpOS0GmgwkVbtr71PTRMjZnNbrJUFU6VNA== + dependencies: + "@react-aria/focus" "^3.19.0" + "@react-aria/form" "^3.0.11" + "@react-aria/label" "^3.7.13" + "@react-aria/utils" "^3.26.0" + "@react-stately/form" "^3.1.0" + "@react-stately/utils" "^3.10.5" + "@react-types/shared" "^3.26.0" + "@react-types/textfield" "^3.10.0" "@swc/helpers" "^0.5.0" -"@react-aria/toggle@^3.10.9": - version "3.10.9" - resolved "https://registry.yarnpkg.com/@react-aria/toggle/-/toggle-3.10.9.tgz#6876cdc963c311d73a11e33031a905b47927063b" - integrity sha512-dtfnyIU2/kcH9rFAiB48diSmaXDv45K7UCuTkMQLjbQa3QHC1oYNbleVN/VdGyAMBsIWtfl8L4uuPrAQmDV/bg== +"@react-aria/toggle@^3.10.10": + version "3.10.10" + resolved "https://registry.yarnpkg.com/@react-aria/toggle/-/toggle-3.10.10.tgz#444658bf606e6d56b1fd96737d5a552c93493979" + integrity sha512-QwMT/vTNrbrILxWVHfd9zVQ3mV2NdBwyRu+DphVQiFAXcmc808LEaIX2n0lI6FCsUDC9ZejCyvzd91/YemdZ1Q== + dependencies: + "@react-aria/focus" "^3.19.0" + "@react-aria/interactions" "^3.22.5" + "@react-aria/utils" "^3.26.0" + "@react-stately/toggle" "^3.8.0" + "@react-types/checkbox" "^3.9.0" + "@react-types/shared" "^3.26.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/toolbar@3.0.0-beta.11": + version "3.0.0-beta.11" + resolved "https://registry.yarnpkg.com/@react-aria/toolbar/-/toolbar-3.0.0-beta.11.tgz#019c9ff2a47ad207504a95afeb0f863cf71a114b" + integrity sha512-LM3jTRFNDgoEpoL568WaiuqiVM7eynSQLJis1hV0vlVnhTd7M7kzt7zoOjzxVb5Uapz02uCp1Fsm4wQMz09qwQ== dependencies: - "@react-aria/focus" "^3.18.4" - "@react-aria/interactions" "^3.22.4" - "@react-aria/utils" "^3.25.3" - "@react-stately/toggle" "^3.7.8" - "@react-types/checkbox" "^3.8.4" - "@react-types/shared" "^3.25.0" + "@react-aria/focus" "^3.19.0" + "@react-aria/i18n" "^3.12.4" + "@react-aria/utils" "^3.26.0" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" "@react-aria/tooltip@^3.7.8": - version "3.7.9" - resolved "https://registry.yarnpkg.com/@react-aria/tooltip/-/tooltip-3.7.9.tgz#8a5f0d44f9988a7ceb55e34664bda07775ae82a2" - integrity sha512-TqVJ7YqaP/enxNyA1QGr43w4nBZmOs6Hb/pROMS5afbX7gHgMVFn0lTRc6DC2cvcfgYc4WICs2QiQMniZt/E7A== - dependencies: - "@react-aria/focus" "^3.18.4" - "@react-aria/interactions" "^3.22.4" - "@react-aria/utils" "^3.25.3" - "@react-stately/tooltip" "^3.4.13" - "@react-types/shared" "^3.25.0" - "@react-types/tooltip" "^3.4.12" + version "3.7.10" + resolved "https://registry.yarnpkg.com/@react-aria/tooltip/-/tooltip-3.7.10.tgz#d710532e80337e50be818dfbf2cc54d0a9b8c592" + integrity sha512-Udi3XOnrF/SYIz72jw9bgB74MG/yCOzF5pozHj2FH2HiJlchYv/b6rHByV/77IZemdlkmL/uugrv/7raPLSlnw== + dependencies: + "@react-aria/focus" "^3.19.0" + "@react-aria/interactions" "^3.22.5" + "@react-aria/utils" "^3.26.0" + "@react-stately/tooltip" "^3.5.0" + "@react-types/shared" "^3.26.0" + "@react-types/tooltip" "^3.4.13" "@swc/helpers" "^0.5.0" -"@react-aria/utils@^3.25.3": - version "3.25.3" - resolved "https://registry.yarnpkg.com/@react-aria/utils/-/utils-3.25.3.tgz#cad9bffc07b045cdc283df2cb65c18747acbf76d" - integrity sha512-PR5H/2vaD8fSq0H/UB9inNbc8KDcVmW6fYAfSWkkn+OAdhTTMVKqXXrZuZBWyFfSD5Ze7VN6acr4hrOQm2bmrA== +"@react-aria/utils@^3.25.3", "@react-aria/utils@^3.26.0": + version "3.26.0" + resolved "https://registry.yarnpkg.com/@react-aria/utils/-/utils-3.26.0.tgz#833cbfa33e75d15835b757791b3f754432d2f948" + integrity sha512-LkZouGSjjQ0rEqo4XJosS4L3YC/zzQkfRM3KoqK6fUOmUJ9t0jQ09WjiF+uOoG9u+p30AVg3TrZRUWmoTS+koQ== dependencies: - "@react-aria/ssr" "^3.9.6" - "@react-stately/utils" "^3.10.4" - "@react-types/shared" "^3.25.0" + "@react-aria/ssr" "^3.9.7" + "@react-stately/utils" "^3.10.5" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" clsx "^2.0.0" -"@react-aria/visually-hidden@^3.8.16", "@react-aria/visually-hidden@^3.8.17": - version "3.8.17" - resolved "https://registry.yarnpkg.com/@react-aria/visually-hidden/-/visually-hidden-3.8.17.tgz#b006aad526d78a9897fcbc793e57ddfe1adbd1af" - integrity sha512-WFgny1q2CbxxU6gu46TGQXf1DjsnuSk+RBDP4M7bm1mUVZzoCp7U7AtjNmsBrWg0NejxUdgD7+7jkHHCQ91qRA== +"@react-aria/visually-hidden@^3.8.16", "@react-aria/visually-hidden@^3.8.18": + version "3.8.18" + resolved "https://registry.yarnpkg.com/@react-aria/visually-hidden/-/visually-hidden-3.8.18.tgz#13c168736944cbe19cd8917ec33a4e6f5f694119" + integrity sha512-l/0igp+uub/salP35SsNWq5mGmg3G5F5QMS1gDZ8p28n7CgjvzyiGhJbbca7Oxvaw1HRFzVl9ev+89I7moNnFQ== dependencies: - "@react-aria/interactions" "^3.22.4" - "@react-aria/utils" "^3.25.3" - "@react-types/shared" "^3.25.0" + "@react-aria/interactions" "^3.22.5" + "@react-aria/utils" "^3.26.0" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" "@react-oauth/google@^0.12.1": @@ -1461,468 +1459,469 @@ resolved "https://registry.yarnpkg.com/@react-oauth/google/-/google-0.12.1.tgz#b76432c3a525e9afe076f787d2ded003fcc1bee9" integrity sha512-qagsy22t+7UdkYAiT5ZhfM4StXi9PPNvw0zuwNmabrWyMKddczMtBIOARflbaIj+wHiQjnMAsZmzsUYuXeyoSg== -"@react-stately/calendar@^3.5.5": - version "3.5.5" - resolved "https://registry.yarnpkg.com/@react-stately/calendar/-/calendar-3.5.5.tgz#52249991e1e9c40921cd3d6dce727c0dd37536cb" - integrity sha512-HzaiDRhrmaYIly8hRsjjIrydLkldiw1Ws6T/130NLQOt+VPwRW/x0R+nil42mA9LZ6oV0XN0NpmG5tn7TaKRGw== +"@react-stately/calendar@^3.5.5", "@react-stately/calendar@^3.6.0": + version "3.6.0" + resolved "https://registry.yarnpkg.com/@react-stately/calendar/-/calendar-3.6.0.tgz#c770890160c33826206a015eb7da32fe8ece81d5" + integrity sha512-GqUtOtGnwWjtNrJud8nY/ywI4VBP5byToNVRTnxbMl+gYO1Qe/uc5NG7zjwMxhb2kqSBHZFdkF0DXVqG2Ul+BA== dependencies: - "@internationalized/date" "^3.5.6" - "@react-stately/utils" "^3.10.4" - "@react-types/calendar" "^3.4.10" - "@react-types/shared" "^3.25.0" + "@internationalized/date" "^3.6.0" + "@react-stately/utils" "^3.10.5" + "@react-types/calendar" "^3.5.0" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-stately/checkbox@^3.6.9": - version "3.6.9" - resolved "https://registry.yarnpkg.com/@react-stately/checkbox/-/checkbox-3.6.9.tgz#e7ff459cb8fe2f57bac37ed666e8304eb70a8ed3" - integrity sha512-JrY3ecnK/SSJPxw+qhGhg3YV4e0CpUcPDrVwY3mSiAE932DPd19xr+qVCknJ34H7JYYt/q0l2z0lmgPnl96RTg== +"@react-stately/checkbox@^3.6.10", "@react-stately/checkbox@^3.6.9": + version "3.6.10" + resolved "https://registry.yarnpkg.com/@react-stately/checkbox/-/checkbox-3.6.10.tgz#69b619fdfcf1e15d2d93392e13289a36d85a8a6c" + integrity sha512-LHm7i4YI8A/RdgWAuADrnSAYIaYYpQeZqsp1a03Og0pJHAlZL0ymN3y2IFwbZueY0rnfM+yF+kWNXjJqbKrFEQ== dependencies: - "@react-stately/form" "^3.0.6" - "@react-stately/utils" "^3.10.4" - "@react-types/checkbox" "^3.8.4" - "@react-types/shared" "^3.25.0" + "@react-stately/form" "^3.1.0" + "@react-stately/utils" "^3.10.5" + "@react-types/checkbox" "^3.9.0" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-stately/collections@^3.11.0": - version "3.11.0" - resolved "https://registry.yarnpkg.com/@react-stately/collections/-/collections-3.11.0.tgz#d04dd728ce4f5036a4e2830b1bbbba36aafd2ef0" - integrity sha512-TiJeJjHMPSbbeAhmCXLJNSCk0fa5XnCvEuYw6HtQzDnYiq1AD7KAwkpjC5NfKkjqF3FLXs/v9RDm/P69q6rYzw== +"@react-stately/collections@^3.11.0", "@react-stately/collections@^3.12.0": + version "3.12.0" + resolved "https://registry.yarnpkg.com/@react-stately/collections/-/collections-3.12.0.tgz#6240d3517d0d86f7d9eb4997108fb432d569e8d7" + integrity sha512-MfR9hwCxe5oXv4qrLUnjidwM50U35EFmInUeFf8i9mskYwWlRYS0O1/9PZ0oF1M0cKambaRHKEy98jczgb9ycA== dependencies: - "@react-types/shared" "^3.25.0" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-stately/color@^3.8.0": - version "3.8.0" - resolved "https://registry.yarnpkg.com/@react-stately/color/-/color-3.8.0.tgz#4527fff1e4e632d35f58ee84493830066f678baa" - integrity sha512-lBH91HEStZeayhE/FkDMt9WC0UISQiAn8DoD2hfpTGeeWscX/soyxZA7oVL7zBOG9RfDBMNzF+CybVROrWSKAQ== - dependencies: - "@internationalized/number" "^3.5.4" - "@internationalized/string" "^3.2.4" - "@react-aria/i18n" "^3.12.3" - "@react-stately/form" "^3.0.6" - "@react-stately/numberfield" "^3.9.7" - "@react-stately/slider" "^3.5.8" - "@react-stately/utils" "^3.10.4" - "@react-types/color" "^3.0.0" - "@react-types/shared" "^3.25.0" +"@react-stately/color@^3.8.0", "@react-stately/color@^3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@react-stately/color/-/color-3.8.1.tgz#13969f61f1c1b468fd891cc94582056fc2da9b9b" + integrity sha512-7eN7K+KJRu+rxK351eGrzoq2cG+yipr90i5b1cUu4lioYmcH4WdsfjmM5Ku6gypbafH+kTDfflvO6hiY1NZH+A== + dependencies: + "@internationalized/number" "^3.6.0" + "@internationalized/string" "^3.2.5" + "@react-aria/i18n" "^3.12.4" + "@react-stately/form" "^3.1.0" + "@react-stately/numberfield" "^3.9.8" + "@react-stately/slider" "^3.6.0" + "@react-stately/utils" "^3.10.5" + "@react-types/color" "^3.0.1" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-stately/combobox@^3.10.0": - version "3.10.0" - resolved "https://registry.yarnpkg.com/@react-stately/combobox/-/combobox-3.10.0.tgz#33667983b8042b6dd342dcea2dd8944e834d4a90" - integrity sha512-4W4HCCjjoddW/LZM3pSSeLoV7ncYXlaICKmqlBcbtLR5jY4U5Kx+pPpy3oJ1vCdjDHatIxZ0tVKEBP7vBQVeGQ== - dependencies: - "@react-stately/collections" "^3.11.0" - "@react-stately/form" "^3.0.6" - "@react-stately/list" "^3.11.0" - "@react-stately/overlays" "^3.6.11" - "@react-stately/select" "^3.6.8" - "@react-stately/utils" "^3.10.4" - "@react-types/combobox" "^3.13.0" - "@react-types/shared" "^3.25.0" +"@react-stately/combobox@^3.10.0", "@react-stately/combobox@^3.10.1": + version "3.10.1" + resolved "https://registry.yarnpkg.com/@react-stately/combobox/-/combobox-3.10.1.tgz#ebae28c5341d06d69cc8e50055fa816dee19522b" + integrity sha512-Rso+H+ZEDGFAhpKWbnRxRR/r7YNmYVtt+Rn0eNDNIUp3bYaxIBCdCySyAtALs4I8RZXZQ9zoUznP7YeVwG3cLg== + dependencies: + "@react-stately/collections" "^3.12.0" + "@react-stately/form" "^3.1.0" + "@react-stately/list" "^3.11.1" + "@react-stately/overlays" "^3.6.12" + "@react-stately/select" "^3.6.9" + "@react-stately/utils" "^3.10.5" + "@react-types/combobox" "^3.13.1" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" "@react-stately/data@^3.11.7": - version "3.11.7" - resolved "https://registry.yarnpkg.com/@react-stately/data/-/data-3.11.7.tgz#3c775ad3e90730abe9a2cd832aa59321f1860d26" - integrity sha512-2YJ+Lmca18f/h7jiZiU9j2IhBJl6BFO1BWlwvcCAH/eCWTdveX8gzsUdW++0szzpJaoCilTCYoi8z7QWyVH9jQ== + version "3.12.0" + resolved "https://registry.yarnpkg.com/@react-stately/data/-/data-3.12.0.tgz#4f0fd89be2fa64ca7c0ad92d8cf20f2cba961fc0" + integrity sha512-6PiW2oA56lcH1CVjDcajutzsv91w/PER8K61/OGxtNFFUWaIZH80RWmK4kjU/Lf0vygzXCxout3kEb388lUk0w== dependencies: - "@react-types/shared" "^3.25.0" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-stately/datepicker@^3.10.3": - version "3.10.3" - resolved "https://registry.yarnpkg.com/@react-stately/datepicker/-/datepicker-3.10.3.tgz#4c7ea07cc1e0d145c8ce1ad406ca44470e654c4c" - integrity sha512-6PJW1QMwk6BQMktV9L6DA4f2rfAdLfbq3iTNLy4qxd5IfNPLMUZiJGGTj+cuqx0WcEl+q5irp+YhKBpbmhPZHg== - dependencies: - "@internationalized/date" "^3.5.6" - "@internationalized/string" "^3.2.4" - "@react-stately/form" "^3.0.6" - "@react-stately/overlays" "^3.6.11" - "@react-stately/utils" "^3.10.4" - "@react-types/datepicker" "^3.8.3" - "@react-types/shared" "^3.25.0" +"@react-stately/datepicker@^3.10.3", "@react-stately/datepicker@^3.11.0": + version "3.11.0" + resolved "https://registry.yarnpkg.com/@react-stately/datepicker/-/datepicker-3.11.0.tgz#5f4daff449f756dc40b4201ae337dd4a3f29facc" + integrity sha512-d9MJF34A0VrhL5y5S8mAISA8uwfNCQKmR2k4KoQJm3De1J8SQeNzSjLviAwh1faDow6FXGlA6tVbTrHyDcBgBg== + dependencies: + "@internationalized/date" "^3.6.0" + "@internationalized/string" "^3.2.5" + "@react-stately/form" "^3.1.0" + "@react-stately/overlays" "^3.6.12" + "@react-stately/utils" "^3.10.5" + "@react-types/datepicker" "^3.9.0" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-stately/dnd@^3.4.3": - version "3.4.3" - resolved "https://registry.yarnpkg.com/@react-stately/dnd/-/dnd-3.4.3.tgz#c9c82729d18e3e48a174a58d607f81458b7785ac" - integrity sha512-sUvhmMxFEw6P2MW7walx0ntakIihxdPxA06K9YZ3+ReaUvzQuRw5cFDaTTHrlegWRMYD0CyQaKlGIaTQihhvVA== +"@react-stately/dnd@^3.4.3", "@react-stately/dnd@^3.5.0": + version "3.5.0" + resolved "https://registry.yarnpkg.com/@react-stately/dnd/-/dnd-3.5.0.tgz#3061233709f7113f6492de33204aea507c243a2e" + integrity sha512-ZcWFw1npEDnATiy3TEdzA1skQ3UEIyfbNA6VhPNO8yiSVLxoxBOaEaq8VVS72fRGAtxud6dgOy8BnsP9JwDClQ== dependencies: - "@react-stately/selection" "^3.17.0" - "@react-types/shared" "^3.25.0" + "@react-stately/selection" "^3.18.0" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-stately/flags@^3.0.4": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@react-stately/flags/-/flags-3.0.4.tgz#ac778647733b6f7c46f4b0f907cec82f08986490" - integrity sha512-RNJEkOALwKg+JeYsfNlfPc4GXm7hiBLX0yuHOkRapWEyDOfi0cinkV/TZG4goOZdQ5tBpHmemf2qqiHAxqHlzQ== +"@react-stately/flags@^3.0.5": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@react-stately/flags/-/flags-3.0.5.tgz#b35bcbd3b80c4f821e23e9c649566a4af11e97bf" + integrity sha512-6wks4csxUwPCp23LgJSnkBRhrWpd9jGd64DjcCTNB2AHIFu7Ab1W59pJpUL6TW7uAxVxdNKjgn6D1hlBy8qWsA== dependencies: "@swc/helpers" "^0.5.0" -"@react-stately/form@^3.0.6": - version "3.0.6" - resolved "https://registry.yarnpkg.com/@react-stately/form/-/form-3.0.6.tgz#788c837a7967a499366928a91738b15dd7f87d77" - integrity sha512-KMsxm3/V0iCv/6ikt4JEjVM3LW2AgCzo7aNotMzRobtwIo0RwaUo7DQNY00rGgFQ3/IjzI6DcVo13D+AVE/zXg== +"@react-stately/form@^3.0.6", "@react-stately/form@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@react-stately/form/-/form-3.1.0.tgz#7fdb4ca153be18e7516a02e507ada393ad38945d" + integrity sha512-E2wxNQ0QaTyDHD0nJFtTSnEH9A3bpJurwxhS4vgcUmESHgjFEMLlC9irUSZKgvOgb42GAq+fHoWBsgKeTp9Big== dependencies: - "@react-types/shared" "^3.25.0" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-stately/grid@^3.9.3": - version "3.9.3" - resolved "https://registry.yarnpkg.com/@react-stately/grid/-/grid-3.9.3.tgz#1ead7cc7b6d036c4609692eaf818a70f472ba8c8" - integrity sha512-P5KgCNYwm/n8bbLx6527li89RQWoESikrsg2MMyUpUd6IJ321t2pGONGRRQzxE0SBMolPRDJKV0Do2OlsjYKhQ== +"@react-stately/grid@^3.10.0": + version "3.10.0" + resolved "https://registry.yarnpkg.com/@react-stately/grid/-/grid-3.10.0.tgz#d74e46f85a662092c61812a8508cf4ac8721ec6d" + integrity sha512-ii+DdsOBvCnHMgL0JvUfFwO1kiAPP19Bpdpl6zn/oOltk6F5TmnoyNrzyz+2///1hCiySI3FE1O7ujsAQs7a6Q== dependencies: - "@react-stately/collections" "^3.11.0" - "@react-stately/selection" "^3.17.0" - "@react-types/grid" "^3.2.9" - "@react-types/shared" "^3.25.0" + "@react-stately/collections" "^3.12.0" + "@react-stately/selection" "^3.18.0" + "@react-types/grid" "^3.2.10" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-stately/list@^3.11.0": - version "3.11.0" - resolved "https://registry.yarnpkg.com/@react-stately/list/-/list-3.11.0.tgz#8bb5d43f6468510562d1023a59f039052a7237f8" - integrity sha512-O+BxXcbtoLZWn4QIT54RoFUaM+QaJQm6s0ZBJ3Jv4ILIhukVOc55ra+aWMVlXFQSpbf6I3hyVP6cz1yyvd5Rtw== +"@react-stately/list@^3.11.0", "@react-stately/list@^3.11.1": + version "3.11.1" + resolved "https://registry.yarnpkg.com/@react-stately/list/-/list-3.11.1.tgz#d1493e5b9c5cac6cafb3cb3a6edb852bf3cb208f" + integrity sha512-UCOpIvqBOjwLtk7zVTYWuKU1m1Oe61Q5lNar/GwHaV1nAiSQ8/yYlhr40NkBEs9X3plEfsV28UIpzOrYnu1tPg== dependencies: - "@react-stately/collections" "^3.11.0" - "@react-stately/selection" "^3.17.0" - "@react-stately/utils" "^3.10.4" - "@react-types/shared" "^3.25.0" + "@react-stately/collections" "^3.12.0" + "@react-stately/selection" "^3.18.0" + "@react-stately/utils" "^3.10.5" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-stately/menu@^3.8.3": - version "3.8.3" - resolved "https://registry.yarnpkg.com/@react-stately/menu/-/menu-3.8.3.tgz#88656fc799ab8591650c87711688a8ccb7986c2e" - integrity sha512-sV63V+cMgzipx/N7dq5GaXoItfXIfFEpCtlk3PM2vKstlCJalszXrdo+x996bkeU96h0plB7znAlhlXOeTKzUg== +"@react-stately/menu@^3.8.3", "@react-stately/menu@^3.9.0": + version "3.9.0" + resolved "https://registry.yarnpkg.com/@react-stately/menu/-/menu-3.9.0.tgz#b1e55996405f4e43ff844cbd325df9842914efe4" + integrity sha512-++sm0fzZeUs9GvtRbj5RwrP+KL9KPANp9f4SvtI3s+MP+Y/X3X7LNNePeeccGeyikB5fzMsuyvd82bRRW9IhDQ== dependencies: - "@react-stately/overlays" "^3.6.11" - "@react-types/menu" "^3.9.12" - "@react-types/shared" "^3.25.0" + "@react-stately/overlays" "^3.6.12" + "@react-types/menu" "^3.9.13" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-stately/numberfield@^3.9.7": - version "3.9.7" - resolved "https://registry.yarnpkg.com/@react-stately/numberfield/-/numberfield-3.9.7.tgz#5685d108339ca627b43158630cba09e84a7f5bf4" - integrity sha512-PjSgCCpYasGCEAznFQNqa2JhhEQ5+/2eMiV7ZI5j76q3edTNF8G5OOCl2RazDbzFp6vDAnRVT7Kctx5Tl5R/Zw== +"@react-stately/numberfield@^3.9.7", "@react-stately/numberfield@^3.9.8": + version "3.9.8" + resolved "https://registry.yarnpkg.com/@react-stately/numberfield/-/numberfield-3.9.8.tgz#863a6c0f7a4249759dd0c586f2e27dd2548aadee" + integrity sha512-J6qGILxDNEtu7yvd3/y+FpbrxEaAeIODwlrFo6z1kvuDlLAm/KszXAc75yoDi0OtakFTCMP6/HR5VnHaQdMJ3w== dependencies: - "@internationalized/number" "^3.5.4" - "@react-stately/form" "^3.0.6" - "@react-stately/utils" "^3.10.4" - "@react-types/numberfield" "^3.8.6" + "@internationalized/number" "^3.6.0" + "@react-stately/form" "^3.1.0" + "@react-stately/utils" "^3.10.5" + "@react-types/numberfield" "^3.8.7" "@swc/helpers" "^0.5.0" -"@react-stately/overlays@^3.6.11": - version "3.6.11" - resolved "https://registry.yarnpkg.com/@react-stately/overlays/-/overlays-3.6.11.tgz#67d413853d47d49ed2687c6b74b1749f4b26da6e" - integrity sha512-usuxitwOx4FbmOW7Og4VM8R8ZjerbHZLLbFaxZW7pWLs7Ypway1YhJ3SWcyNTYK7NEk4o602kSoU6MSev1Vgag== +"@react-stately/overlays@^3.6.11", "@react-stately/overlays@^3.6.12": + version "3.6.12" + resolved "https://registry.yarnpkg.com/@react-stately/overlays/-/overlays-3.6.12.tgz#beb594a0e140dbd7957bfa181006854f91480bea" + integrity sha512-QinvZhwZgj8obUyPIcyURSCjTZlqZYRRCS60TF8jH8ZpT0tEAuDb3wvhhSXuYA3Xo9EHLwvLjEf3tQKKdAQArw== dependencies: - "@react-stately/utils" "^3.10.4" - "@react-types/overlays" "^3.8.10" + "@react-stately/utils" "^3.10.5" + "@react-types/overlays" "^3.8.11" "@swc/helpers" "^0.5.0" -"@react-stately/radio@^3.10.8": - version "3.10.8" - resolved "https://registry.yarnpkg.com/@react-stately/radio/-/radio-3.10.8.tgz#1b6e146dc402ce9de05176be6fd75ed260a674c5" - integrity sha512-VRq6Gzsbk3jzX6hdrSoDoSra9vLRsOi2pLkvW/CMrJ0GSgMwr8jjvJKnNFvYJ3eYQb20EwkarsOAfk7vPSIt/Q== +"@react-stately/radio@^3.10.8", "@react-stately/radio@^3.10.9": + version "3.10.9" + resolved "https://registry.yarnpkg.com/@react-stately/radio/-/radio-3.10.9.tgz#cf74b8f47cbef56836424d2e7d06c01fe9d9ea05" + integrity sha512-kUQ7VdqFke8SDRCatw2jW3rgzMWbvw+n2imN2THETynI47NmNLzNP11dlGO2OllRtTrsLhmBNlYHa3W62pFpAw== dependencies: - "@react-stately/form" "^3.0.6" - "@react-stately/utils" "^3.10.4" - "@react-types/radio" "^3.8.4" - "@react-types/shared" "^3.25.0" + "@react-stately/form" "^3.1.0" + "@react-stately/utils" "^3.10.5" + "@react-types/radio" "^3.8.5" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-stately/searchfield@^3.5.7": - version "3.5.7" - resolved "https://registry.yarnpkg.com/@react-stately/searchfield/-/searchfield-3.5.7.tgz#7cfe3ec976f59cbda038bef775abe66e3b5bbf15" - integrity sha512-VxEG4tWDypdXQ8f7clZBu5Qmc4osqDBeA/gNMA2i1j/h2zRVcCJ0fRCHuDeXLSWBqF1XXAI4TWV53fBBwJusbg== +"@react-stately/searchfield@^3.5.7", "@react-stately/searchfield@^3.5.8": + version "3.5.8" + resolved "https://registry.yarnpkg.com/@react-stately/searchfield/-/searchfield-3.5.8.tgz#b927e25afd32b1a32f22d54df6d7b4968cb4cf33" + integrity sha512-jtquvGadx1DmtQqPKaVO6Qg/xpBjNxsOd59ciig9xRxpxV+90i996EX1E2R6R+tGJdSM1pD++7PVOO4yE++HOg== dependencies: - "@react-stately/utils" "^3.10.4" - "@react-types/searchfield" "^3.5.9" + "@react-stately/utils" "^3.10.5" + "@react-types/searchfield" "^3.5.10" "@swc/helpers" "^0.5.0" -"@react-stately/select@^3.6.8": - version "3.6.8" - resolved "https://registry.yarnpkg.com/@react-stately/select/-/select-3.6.8.tgz#37d331a4cf248c428aad5fc1349a7cdcae12f89b" - integrity sha512-fLAVzGeYSdYdBdrEVws6Pb1ywFPdapA0eWphoW5s3fS0/pKcVWwbCHeHlaBEi1ISyqEubQZFGQdeFKm/M46Hew== - dependencies: - "@react-stately/form" "^3.0.6" - "@react-stately/list" "^3.11.0" - "@react-stately/overlays" "^3.6.11" - "@react-types/select" "^3.9.7" - "@react-types/shared" "^3.25.0" +"@react-stately/select@^3.6.8", "@react-stately/select@^3.6.9": + version "3.6.9" + resolved "https://registry.yarnpkg.com/@react-stately/select/-/select-3.6.9.tgz#088bb0fe7b16cc67d833f17c330df63c4310a5da" + integrity sha512-vASUDv7FhEYQURzM+JIwcusPv7/x/l3zHc/oKJPvoCl3aa9pwS8hZwS82SC00o2iFnrDscfDJju4IE/cd4hucg== + dependencies: + "@react-stately/form" "^3.1.0" + "@react-stately/list" "^3.11.1" + "@react-stately/overlays" "^3.6.12" + "@react-types/select" "^3.9.8" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-stately/selection@^3.17.0": - version "3.17.0" - resolved "https://registry.yarnpkg.com/@react-stately/selection/-/selection-3.17.0.tgz#92ada2cfe00bf47a5c4a53b2809c6703d71a9798" - integrity sha512-It3LRTaFOavybuDBvBH2mvCh73OL4awqvN4tZ0JzLzMtaYSBe9+YmFasYrzB0o7ca17B2q1tpUmsNWaAgIqbLA== +"@react-stately/selection@^3.17.0", "@react-stately/selection@^3.18.0": + version "3.18.0" + resolved "https://registry.yarnpkg.com/@react-stately/selection/-/selection-3.18.0.tgz#eb723dc26eafd9b016c55056fb550bdde8b4f87b" + integrity sha512-6EaNNP3exxBhW2LkcRR4a3pg+3oDguZlBSqIVVR7lyahv/D8xXHRC4dX+m0mgGHJpsgjs7664Xx6c8v193TFxg== dependencies: - "@react-stately/collections" "^3.11.0" - "@react-stately/utils" "^3.10.4" - "@react-types/shared" "^3.25.0" + "@react-stately/collections" "^3.12.0" + "@react-stately/utils" "^3.10.5" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-stately/slider@^3.5.8": - version "3.5.8" - resolved "https://registry.yarnpkg.com/@react-stately/slider/-/slider-3.5.8.tgz#b5370f2bc0b8833a191b9ce1e0d48e49d4b44972" - integrity sha512-EDgbrxMq1w3+XTN72MGl3YtAG/j65EYX1Uc3Fh56K00+inJbTdRWyYTrb3NA310fXCd0WFBbzExuH2ohlKQycg== +"@react-stately/slider@^3.5.8", "@react-stately/slider@^3.6.0": + version "3.6.0" + resolved "https://registry.yarnpkg.com/@react-stately/slider/-/slider-3.6.0.tgz#20439e08915725c4f6ba2285a561ae92fe59d997" + integrity sha512-w5vJxVh267pmD1X+Ppd9S3ZzV1hcg0cV8q5P4Egr160b9WMcWlUspZPtsthwUlN7qQe/C8y5IAhtde4s29eNag== dependencies: - "@react-stately/utils" "^3.10.4" - "@react-types/shared" "^3.25.0" - "@react-types/slider" "^3.7.6" + "@react-stately/utils" "^3.10.5" + "@react-types/shared" "^3.26.0" + "@react-types/slider" "^3.7.7" "@swc/helpers" "^0.5.0" -"@react-stately/table@^3.12.3": - version "3.12.3" - resolved "https://registry.yarnpkg.com/@react-stately/table/-/table-3.12.3.tgz#aae5fa267af2de6ed77a79b8482758ffdd318e80" - integrity sha512-8uGrLcNJYeMbFtzRQZFWCBj5kV+7v3jzwoKIL1j9TmYUKow1PTDMQbPJpAZLQhnC2wVMlaFVgDbedSlbBij7Zg== - dependencies: - "@react-stately/collections" "^3.11.0" - "@react-stately/flags" "^3.0.4" - "@react-stately/grid" "^3.9.3" - "@react-stately/selection" "^3.17.0" - "@react-stately/utils" "^3.10.4" - "@react-types/grid" "^3.2.9" - "@react-types/shared" "^3.25.0" - "@react-types/table" "^3.10.2" +"@react-stately/table@^3.12.3", "@react-stately/table@^3.13.0": + version "3.13.0" + resolved "https://registry.yarnpkg.com/@react-stately/table/-/table-3.13.0.tgz#8465030f568b5ee779623d99b2ef22940a99a6cd" + integrity sha512-mRbNYrwQIE7xzVs09Lk3kPteEVFVyOc20vA8ph6EP54PiUf/RllJpxZe/WUYLf4eom9lUkRYej5sffuUBpxjCA== + dependencies: + "@react-stately/collections" "^3.12.0" + "@react-stately/flags" "^3.0.5" + "@react-stately/grid" "^3.10.0" + "@react-stately/selection" "^3.18.0" + "@react-stately/utils" "^3.10.5" + "@react-types/grid" "^3.2.10" + "@react-types/shared" "^3.26.0" + "@react-types/table" "^3.10.3" "@swc/helpers" "^0.5.0" -"@react-stately/tabs@^3.6.10": - version "3.6.10" - resolved "https://registry.yarnpkg.com/@react-stately/tabs/-/tabs-3.6.10.tgz#89543e109e473b308ec12f2bc62ba99c74038f70" - integrity sha512-F7wfoiNsrBy7c02AYHyE1USGgj05HQ0hp7uXmQjp2LEa+AA0NKKi3HdswTHHySxb0ZRuoEE7E7vp/gXQYx2/Ow== +"@react-stately/tabs@^3.6.10", "@react-stately/tabs@^3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@react-stately/tabs/-/tabs-3.7.0.tgz#f849b334c5e7d39a37c2e9ffa3114531bf8ce6e4" + integrity sha512-ox4hTkfZCoR4Oyr3Op3rBlWNq2Wxie04vhEYpTZQ2hobR3l4fYaOkd7CPClILktJ3TC104j8wcb0knWxIBRx9w== dependencies: - "@react-stately/list" "^3.11.0" - "@react-types/shared" "^3.25.0" - "@react-types/tabs" "^3.3.10" + "@react-stately/list" "^3.11.1" + "@react-types/shared" "^3.26.0" + "@react-types/tabs" "^3.3.11" "@swc/helpers" "^0.5.0" -"@react-stately/toggle@^3.7.8": - version "3.7.8" - resolved "https://registry.yarnpkg.com/@react-stately/toggle/-/toggle-3.7.8.tgz#14bcc21a50c7196c084542aa83584db86c911d13" - integrity sha512-ySOtkByvIY54yIu8IZ4lnvomQA0H+/mkZnd6T5fKN3tjvIzHmkUk3TAPmNInUxHX148tSW6mWwec0xvjYqEd6w== +"@react-stately/toggle@^3.7.8", "@react-stately/toggle@^3.8.0": + version "3.8.0" + resolved "https://registry.yarnpkg.com/@react-stately/toggle/-/toggle-3.8.0.tgz#39a3e45989f56e236809d8fe69c160cc88a616f5" + integrity sha512-pyt/k/J8BwE/2g6LL6Z6sMSWRx9HEJB83Sm/MtovXnI66sxJ2EfQ1OaXB7Su5PEL9OMdoQF6Mb+N1RcW3zAoPw== dependencies: - "@react-stately/utils" "^3.10.4" - "@react-types/checkbox" "^3.8.4" + "@react-stately/utils" "^3.10.5" + "@react-types/checkbox" "^3.9.0" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-stately/tooltip@^3.4.13": - version "3.4.13" - resolved "https://registry.yarnpkg.com/@react-stately/tooltip/-/tooltip-3.4.13.tgz#72381ef42afd6731d4a1b51c30632bb8d07f1757" - integrity sha512-zQ+8FQ7Pi0Cz852dltXb6yaryjE18K3byK4tIO3e5vnrZHEGvfdxowc+v9ak5UV93kVrYoOVmfZHRcEaTXTBNA== +"@react-stately/tooltip@^3.4.13", "@react-stately/tooltip@^3.5.0": + version "3.5.0" + resolved "https://registry.yarnpkg.com/@react-stately/tooltip/-/tooltip-3.5.0.tgz#1016952eb4427d5b848e2efcb24eee47e2a26b59" + integrity sha512-+xzPNztJDd2XJD0X3DgWKlrgOhMqZpSzsIssXeJgO7uCnP8/Z513ESaipJhJCFC8fxj5caO/DK4Uu8hEtlB8cQ== dependencies: - "@react-stately/overlays" "^3.6.11" - "@react-types/tooltip" "^3.4.12" + "@react-stately/overlays" "^3.6.12" + "@react-types/tooltip" "^3.4.13" "@swc/helpers" "^0.5.0" -"@react-stately/tree@^3.8.5": - version "3.8.5" - resolved "https://registry.yarnpkg.com/@react-stately/tree/-/tree-3.8.5.tgz#4c08d29c75a809265c7ead00b78e26d10bb7aea7" - integrity sha512-0/tYhsKWQQJTOZFDwh8hY3Qk6ejNFRldGrLeK5kS22UZdvsMFyh7WAi40FTCJy561/VoB0WqQI4oyNPOa9lYWg== +"@react-stately/tree@^3.8.5", "@react-stately/tree@^3.8.6": + version "3.8.6" + resolved "https://registry.yarnpkg.com/@react-stately/tree/-/tree-3.8.6.tgz#85dc33c5d5b9a455ffc0b474300957e511db1ea4" + integrity sha512-lblUaxf1uAuIz5jm6PYtcJ+rXNNVkqyFWTIMx6g6gW/mYvm8GNx1G/0MLZE7E6CuDGaO9dkLSY2bB1uqyKHidA== dependencies: - "@react-stately/collections" "^3.11.0" - "@react-stately/selection" "^3.17.0" - "@react-stately/utils" "^3.10.4" - "@react-types/shared" "^3.25.0" + "@react-stately/collections" "^3.12.0" + "@react-stately/selection" "^3.18.0" + "@react-stately/utils" "^3.10.5" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-stately/utils@^3.10.4": - version "3.10.4" - resolved "https://registry.yarnpkg.com/@react-stately/utils/-/utils-3.10.4.tgz#310663a834b67048d305e1680ed258130092fe51" - integrity sha512-gBEQEIMRh5f60KCm7QKQ2WfvhB2gLUr9b72sqUdIZ2EG+xuPgaIlCBeSicvjmjBvYZwOjoOEnmIkcx2GHp/HWw== +"@react-stately/utils@^3.10.5": + version "3.10.5" + resolved "https://registry.yarnpkg.com/@react-stately/utils/-/utils-3.10.5.tgz#47bb91cd5afd1bafe39353614e5e281b818ebccc" + integrity sha512-iMQSGcpaecghDIh3mZEpZfoFH3ExBwTtuBEcvZ2XnGzCgQjeYXcMdIUwAfVQLXFTdHUHGF6Gu6/dFrYsCzySBQ== dependencies: "@swc/helpers" "^0.5.0" -"@react-types/breadcrumbs@^3.7.8": - version "3.7.8" - resolved "https://registry.yarnpkg.com/@react-types/breadcrumbs/-/breadcrumbs-3.7.8.tgz#edcde11c06bad19008a066fa0a91eb5fda9723f5" - integrity sha512-+BW2a+PrY8ArZ+pKecz13oJFrUAhthvXx17o3x0BhWUhRpAdtmTYt2hjw8zNanm2j0Kvgo1HYKgvtskCRxYcOA== +"@react-types/breadcrumbs@^3.7.9": + version "3.7.9" + resolved "https://registry.yarnpkg.com/@react-types/breadcrumbs/-/breadcrumbs-3.7.9.tgz#c75eae6158bd3631854bff7521c2373b42b0e37c" + integrity sha512-eARYJo8J+VfNV8vP4uw3L2Qliba9wLV2bx9YQCYf5Lc/OE5B/y4gaTLz+Y2P3Rtn6gBPLXY447zCs5i7gf+ICg== dependencies: - "@react-types/link" "^3.5.8" - "@react-types/shared" "^3.25.0" + "@react-types/link" "^3.5.9" + "@react-types/shared" "^3.26.0" -"@react-types/button@^3.10.0": - version "3.10.0" - resolved "https://registry.yarnpkg.com/@react-types/button/-/button-3.10.0.tgz#5044648401f9842c47a433c66180a5a520cc29af" - integrity sha512-rAyU+N9VaHLBdZop4zasn8IDwf9I5Q1EzHUKMtzIFf5aUlMUW+K460zI/l8UESWRSWAXK9/WPSXGxfcoCEjvAA== +"@react-types/button@^3.10.1": + version "3.10.1" + resolved "https://registry.yarnpkg.com/@react-types/button/-/button-3.10.1.tgz#fc7ada2e83bc661b31c1473a82ec86dc11de057c" + integrity sha512-XTtap8o04+4QjPNAshFWOOAusUTxQlBjU2ai0BTVLShQEjHhRVDBIWsI2B2FKJ4KXT6AZ25llaxhNrreWGonmA== dependencies: - "@react-types/shared" "^3.25.0" + "@react-types/shared" "^3.26.0" -"@react-types/calendar@^3.4.10": - version "3.4.10" - resolved "https://registry.yarnpkg.com/@react-types/calendar/-/calendar-3.4.10.tgz#65011c31fb497e25bd98d19c84da3b8d63d5a3aa" - integrity sha512-PyjqxwJxSW2IpQx6y0D9O34fRCWn1gv9q0qFhgaIigIQrPg8zTE/CC7owHLxAtgCnnCt8exJ5rqi414csaHKlA== +"@react-types/calendar@^3.5.0": + version "3.5.0" + resolved "https://registry.yarnpkg.com/@react-types/calendar/-/calendar-3.5.0.tgz#a72fa15e08c7785b145005560baa35ad9b44627b" + integrity sha512-O3IRE7AGwAWYnvJIJ80cOy7WwoJ0m8GtX/qSmvXQAjC4qx00n+b5aFNBYAQtcyc3RM5QpW6obs9BfwGetFiI8w== dependencies: - "@internationalized/date" "^3.5.6" - "@react-types/shared" "^3.25.0" + "@internationalized/date" "^3.6.0" + "@react-types/shared" "^3.26.0" -"@react-types/checkbox@^3.8.4": - version "3.8.4" - resolved "https://registry.yarnpkg.com/@react-types/checkbox/-/checkbox-3.8.4.tgz#a51b90025fd362d8b755d8a95640a0134124f688" - integrity sha512-fvZrlQmlFNsYHZpl7GVmyYQlKdUtO5MczMSf8z3TlSiCb5Kl3ha9PsZgLhJqGuVnzB2ArIBz0eZrYa3k0PhcpA== +"@react-types/checkbox@^3.9.0": + version "3.9.0" + resolved "https://registry.yarnpkg.com/@react-types/checkbox/-/checkbox-3.9.0.tgz#d4621fef81850543f7a028917e9c2781cd871443" + integrity sha512-9hbHx0Oo2Hp5a8nV8Q75LQR0DHtvOIJbFaeqESSopqmV9EZoYjtY/h0NS7cZetgahQgnqYWQi44XGooMDCsmxA== dependencies: - "@react-types/shared" "^3.25.0" + "@react-types/shared" "^3.26.0" -"@react-types/color@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@react-types/color/-/color-3.0.0.tgz#85965ce25e5d86e544b9be3603fd59c60c087d3c" - integrity sha512-VUH8CROAM69GsMBilrJ1xyAdVsWL01nXQYrkZJxAEApv1OrcpIGSdsXLcGrjsrhjjiNVXxWFnqYRMsKkLzIl7g== +"@react-types/color@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@react-types/color/-/color-3.0.1.tgz#42d49736cf606b8434d3fe0ab60b75bb0f44f554" + integrity sha512-KemFziO3GbmT3HEKrgOGdqNA6Gsmy9xrwFO3f8qXSG7gVz6M27Ic4R9HVQv4iAjap5uti6W13/pk2bc/jLVcEA== dependencies: - "@react-types/shared" "^3.25.0" - "@react-types/slider" "^3.7.6" + "@react-types/shared" "^3.26.0" + "@react-types/slider" "^3.7.7" -"@react-types/combobox@^3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@react-types/combobox/-/combobox-3.13.0.tgz#2969ae4121c6d4c7a9e843530f60d9da6b520f49" - integrity sha512-kH/a+Fjpr54M2JbHg9RXwMjZ9O+XVsdOuE5JCpWRibJP1Mfl1md8gY6y6zstmVY8COrSqFvMZWB+PzwaTWjTGw== +"@react-types/combobox@^3.13.1": + version "3.13.1" + resolved "https://registry.yarnpkg.com/@react-types/combobox/-/combobox-3.13.1.tgz#d7d843f45501ad141f74ba62ed46d2e991b2d6a0" + integrity sha512-7xr+HknfhReN4QPqKff5tbKTe2kGZvH+DGzPYskAtb51FAAiZsKo+WvnNAvLwg3kRoC9Rkn4TAiVBp/HgymRDw== dependencies: - "@react-types/shared" "^3.25.0" + "@react-types/shared" "^3.26.0" -"@react-types/datepicker@^3.8.3": - version "3.8.3" - resolved "https://registry.yarnpkg.com/@react-types/datepicker/-/datepicker-3.8.3.tgz#3d54003a92c3a37f35309373ddbb9c663135b631" - integrity sha512-Y4qfPRBB6uzocosCOWSYMuwiZ3YXwLWQYiFB4KCglkvHyltbNz76LgoBEnclYA5HjwosIk4XywiXvHSYry8JnQ== +"@react-types/datepicker@^3.9.0": + version "3.9.0" + resolved "https://registry.yarnpkg.com/@react-types/datepicker/-/datepicker-3.9.0.tgz#86e2a4e23e9fbf8299a12bd8aba9b1a52cf44725" + integrity sha512-dbKL5Qsm2MQwOTtVQdOcKrrphcXAqDD80WLlSQrBLg+waDuuQ7H+TrvOT0thLKloNBlFUGnZZfXGRHINpih/0g== dependencies: - "@internationalized/date" "^3.5.6" - "@react-types/calendar" "^3.4.10" - "@react-types/overlays" "^3.8.10" - "@react-types/shared" "^3.25.0" + "@internationalized/date" "^3.6.0" + "@react-types/calendar" "^3.5.0" + "@react-types/overlays" "^3.8.11" + "@react-types/shared" "^3.26.0" -"@react-types/dialog@^3.5.13": - version "3.5.13" - resolved "https://registry.yarnpkg.com/@react-types/dialog/-/dialog-3.5.13.tgz#7100f9d5a25626cea2d2d8a755f4c0aa625faa68" - integrity sha512-9k8daVcAqQsySkzDY6NIVlyGxtpEip4TKuLyzAehthbv78GQardD5fHdjQ6eXPRS4I2qZrmytrFFrlOnwWVGHw== +"@react-types/dialog@^3.5.14": + version "3.5.14" + resolved "https://registry.yarnpkg.com/@react-types/dialog/-/dialog-3.5.14.tgz#97e568dc38ede4312ba6a12eda855c5e32c7cd47" + integrity sha512-OXWMjrALwrlgw8aHD8SeRm/s3tbAssdaEh2h73KUSeFau3fU3n5mfKv+WnFqsEaOtN261o48l7hTlS6615H9AA== dependencies: - "@react-types/overlays" "^3.8.10" - "@react-types/shared" "^3.25.0" + "@react-types/overlays" "^3.8.11" + "@react-types/shared" "^3.26.0" -"@react-types/grid@^3.2.9": - version "3.2.9" - resolved "https://registry.yarnpkg.com/@react-types/grid/-/grid-3.2.9.tgz#2a3e7b78cdca2df60e408b6f4f2bc6173ac98a0e" - integrity sha512-eMw0d2UIZ4QTzGgD1wGGPw0cv67KjAOCp4TcwWjgDV7Wa5SVV/UvOmpnIVDyfhkG/4KRI5OR9h+isy76B726qA== +"@react-types/grid@^3.2.10": + version "3.2.10" + resolved "https://registry.yarnpkg.com/@react-types/grid/-/grid-3.2.10.tgz#d2d1d124ed9472e3dedc48e91c941a7ad23bdc83" + integrity sha512-Z5cG0ITwqjUE4kWyU5/7VqiPl4wqMJ7kG/ZP7poAnLmwRsR8Ai0ceVn+qzp5nTA19cgURi8t3LsXn3Ar1FBoog== dependencies: - "@react-types/shared" "^3.25.0" + "@react-types/shared" "^3.26.0" -"@react-types/link@^3.5.8": - version "3.5.8" - resolved "https://registry.yarnpkg.com/@react-types/link/-/link-3.5.8.tgz#6a21ec7999cc1a5dbc71456b0739e27054114c3a" - integrity sha512-l/YGXddgAbLnIT7ekftXrK1D4n8NlLQwx0d4usyZpaxP1KwPzuwng20DxynamLc1atoKBqbUtZAnz32pe7vYgw== +"@react-types/link@^3.5.9": + version "3.5.9" + resolved "https://registry.yarnpkg.com/@react-types/link/-/link-3.5.9.tgz#bf61ff2780581de03920e6e43260844a81a38d2f" + integrity sha512-JcKDiDMqrq/5Vpn+BdWQEuXit4KN4HR/EgIi3yKnNbYkLzxBoeQZpQgvTaC7NEQeZnSqkyXQo3/vMUeX/ZNIKw== dependencies: - "@react-types/shared" "^3.25.0" + "@react-types/shared" "^3.26.0" -"@react-types/listbox@^3.5.2": - version "3.5.2" - resolved "https://registry.yarnpkg.com/@react-types/listbox/-/listbox-3.5.2.tgz#4a807338574e0560d0411b6ce60661d4ca74be6b" - integrity sha512-ML/Bt/MeO0FiixcuFQ+smpu1WguxTOqHDjSnhc1vcNxVQFWQOhyVy01LAY2J/T9TjfjyYGD41vyMTI0f6fcLEQ== +"@react-types/listbox@^3.5.3": + version "3.5.3" + resolved "https://registry.yarnpkg.com/@react-types/listbox/-/listbox-3.5.3.tgz#c5dbe8a67d67ca59de6b88aaa2f20fcf61fee1c5" + integrity sha512-v1QXd9/XU3CCKr2Vgs7WLcTr6VMBur7CrxHhWZQQFExsf9bgJ/3wbUdjy4aThY/GsYHiaS38EKucCZFr1QAfqA== dependencies: - "@react-types/shared" "^3.25.0" + "@react-types/shared" "^3.26.0" -"@react-types/menu@^3.9.12": - version "3.9.12" - resolved "https://registry.yarnpkg.com/@react-types/menu/-/menu-3.9.12.tgz#d8dd7ec5bdc4435db463cf56e79219a0f4a1a667" - integrity sha512-1SPnkHKJdvOfwv9fEgK1DI6DYRs4D3hW2XcWlLhVXSjaC68CzOHGwFhKIKvZiDTW/11L770PRSEloIxHR09uFQ== +"@react-types/menu@^3.9.13": + version "3.9.13" + resolved "https://registry.yarnpkg.com/@react-types/menu/-/menu-3.9.13.tgz#a666c2233cbdb495202586df86a798601788f74d" + integrity sha512-7SuX6E2tDsqQ+HQdSvIda1ji/+ujmR86dtS9CUu5yWX91P25ufRjZ72EvLRqClWNQsj1Xl4+2zBDLWlceznAjw== dependencies: - "@react-types/overlays" "^3.8.10" - "@react-types/shared" "^3.25.0" + "@react-types/overlays" "^3.8.11" + "@react-types/shared" "^3.26.0" -"@react-types/meter@^3.4.4": - version "3.4.4" - resolved "https://registry.yarnpkg.com/@react-types/meter/-/meter-3.4.4.tgz#e554eafa4583883b1f29bdc42a54e59c1a72e468" - integrity sha512-0SEmPkShByC1gYkW7l+iJPg8QfEe2VrgwTciAtTfC4KIqAYmJVQtq6L+4d72EMxOh8RpQHePaY/RFHEJXAh72A== +"@react-types/meter@^3.4.5": + version "3.4.5" + resolved "https://registry.yarnpkg.com/@react-types/meter/-/meter-3.4.5.tgz#e06d4a2fabd24989c73541b032123c5de495b613" + integrity sha512-04w1lEtvP/c3Ep8ND8hhH2rwjz2MtQ8o8SNLhahen3u0rX3jKOgD4BvHujsyvXXTMjj1Djp74sGzNawb4Ppi9w== dependencies: - "@react-types/progress" "^3.5.7" + "@react-types/progress" "^3.5.8" -"@react-types/numberfield@^3.8.6": - version "3.8.6" - resolved "https://registry.yarnpkg.com/@react-types/numberfield/-/numberfield-3.8.6.tgz#58bf9d5157f5c217a198a284a11382fb5bbb737f" - integrity sha512-VtWEMAXUO1S9EEZI8whc7xv6DVccxhbWsRthMCg/LxiwU3U5KAveadNc2c5rtXkRpd3cnD5xFzz3dExXdmHkAg== +"@react-types/numberfield@^3.8.7": + version "3.8.7" + resolved "https://registry.yarnpkg.com/@react-types/numberfield/-/numberfield-3.8.7.tgz#5a697fdf1bc405dbf55dafed713d47ed79f8e54b" + integrity sha512-KccMPi39cLoVkB2T0V7HW6nsxQVAwt89WWCltPZJVGzsebv/k0xTQlPVAgrUake4kDLoE687e3Fr/Oe3+1bDhw== dependencies: - "@react-types/shared" "^3.25.0" + "@react-types/shared" "^3.26.0" -"@react-types/overlays@^3.8.10": - version "3.8.10" - resolved "https://registry.yarnpkg.com/@react-types/overlays/-/overlays-3.8.10.tgz#9315b7d376f2877ef531cb42217327833eabcd15" - integrity sha512-IcnB+VYfAJazRjWhBKZTmVMh3KTp/B1rRbcKkPx6t8djP9UQhKcohP7lAALxjJ56Jjz/GFC6rWyUcnYH0NFVRA== +"@react-types/overlays@^3.8.11": + version "3.8.11" + resolved "https://registry.yarnpkg.com/@react-types/overlays/-/overlays-3.8.11.tgz#313964703b2a23572138120b619d35da33445dfd" + integrity sha512-aw7T0rwVI3EuyG5AOaEIk8j7dZJQ9m34XAztXJVZ/W2+4pDDkLDbJ/EAPnuo2xGYRGhowuNDn4tDju01eHYi+w== dependencies: - "@react-types/shared" "^3.25.0" + "@react-types/shared" "^3.26.0" -"@react-types/progress@^3.5.7": - version "3.5.7" - resolved "https://registry.yarnpkg.com/@react-types/progress/-/progress-3.5.7.tgz#adba7b5a15163f9c523a00a681513aa37e688314" - integrity sha512-EqMDHmlpoZUZzTjdejGIkSM0pS2LBI9NdadHf3bDNTycHv+5L1xpMHUg8RGOW8a3sRVLRvfN1aO9l75QZkyj+w== +"@react-types/progress@^3.5.8": + version "3.5.8" + resolved "https://registry.yarnpkg.com/@react-types/progress/-/progress-3.5.8.tgz#62ce4207c7e8d640b794c6d89063ce21bdb5970d" + integrity sha512-PR0rN5mWevfblR/zs30NdZr+82Gka/ba7UHmYOW9/lkKlWeD7PHgl1iacpd/3zl/jUF22evAQbBHmk1mS6Mpqw== dependencies: - "@react-types/shared" "^3.25.0" + "@react-types/shared" "^3.26.0" -"@react-types/radio@^3.8.4": - version "3.8.4" - resolved "https://registry.yarnpkg.com/@react-types/radio/-/radio-3.8.4.tgz#5133d4cd666f20d2449941ca88abe6e56a5c07ff" - integrity sha512-GCuOwQL19iwKa74NAIk9hv4ivyI8oW1+ZCuc2fzyDdeQjzTIlv3qrIyShwpVy1IoI7/4DYTMZm/YXPoKhu5TTA== +"@react-types/radio@^3.8.5": + version "3.8.5" + resolved "https://registry.yarnpkg.com/@react-types/radio/-/radio-3.8.5.tgz#8e2dd1911fba829b7f1ebb40bccf9ca483f021fc" + integrity sha512-gSImTPid6rsbJmwCkTliBIU/npYgJHOFaI3PNJo7Y0QTAnFelCtYeFtBiWrFodSArSv7ASqpLLUEj9hZu/rxIg== dependencies: - "@react-types/shared" "^3.25.0" + "@react-types/shared" "^3.26.0" -"@react-types/searchfield@^3.5.9": - version "3.5.9" - resolved "https://registry.yarnpkg.com/@react-types/searchfield/-/searchfield-3.5.9.tgz#c7cd9902fd9057baf1eb156dc21e1d7436187ae2" - integrity sha512-c/x8BWpH1Zq+fWpeBtzw2AhQhGi7ahWPicV7PlnqwIGO0MrH/QCjX0dj+I+1xpcAh8Eq6ECa79HE74Rw6aJmFg== +"@react-types/searchfield@^3.5.10": + version "3.5.10" + resolved "https://registry.yarnpkg.com/@react-types/searchfield/-/searchfield-3.5.10.tgz#015a42bf8417618b848035b88f0aba98572beceb" + integrity sha512-7wW4pJzbReawoGPu8a4l+CODTCDN088EN/ysUzl622ewim57PjArjix+lpO4+aEtJqS9HKpq8UEbjwo9axpcUA== dependencies: - "@react-types/shared" "^3.25.0" - "@react-types/textfield" "^3.9.7" + "@react-types/shared" "^3.26.0" + "@react-types/textfield" "^3.10.0" -"@react-types/select@^3.9.7": - version "3.9.7" - resolved "https://registry.yarnpkg.com/@react-types/select/-/select-3.9.7.tgz#d339cca27414c4f6e0bb5c9501a20d0c6249df42" - integrity sha512-Jva4ixfB4EEdy+WmZkUoLiQI7vVfHPxM73VuL7XDxvAO+YKiIztDTcU720QVNhxTMmQvCxfRBXWar8aodCjLiw== +"@react-types/select@^3.9.8": + version "3.9.8" + resolved "https://registry.yarnpkg.com/@react-types/select/-/select-3.9.8.tgz#2443b82549b65821f85876a5b803e6d04ae6343e" + integrity sha512-RGsYj2oFjXpLnfcvWMBQnkcDuKkwT43xwYWZGI214/gp/B64tJiIUgTM5wFTRAeGDX23EePkhCQF+9ctnqFd6g== dependencies: - "@react-types/shared" "^3.25.0" + "@react-types/shared" "^3.26.0" -"@react-types/shared@^3.25.0": - version "3.25.0" - resolved "https://registry.yarnpkg.com/@react-types/shared/-/shared-3.25.0.tgz#7223baf72256e918a3c29081bb1ecc6fad4fbf58" - integrity sha512-OZSyhzU6vTdW3eV/mz5i6hQwQUhkRs7xwY2d1aqPvTdMe0+2cY7Fwp45PAiwYLEj73i9ro2FxF9qC4DvHGSCgQ== +"@react-types/shared@^3.25.0", "@react-types/shared@^3.26.0": + version "3.26.0" + resolved "https://registry.yarnpkg.com/@react-types/shared/-/shared-3.26.0.tgz#21a8b579f0097ee78de18e3e580421ced89e4c8c" + integrity sha512-6FuPqvhmjjlpEDLTiYx29IJCbCNWPlsyO+ZUmCUXzhUv2ttShOXfw8CmeHWHftT/b2KweAWuzqSlfeXPR76jpw== -"@react-types/slider@^3.7.6": - version "3.7.6" - resolved "https://registry.yarnpkg.com/@react-types/slider/-/slider-3.7.6.tgz#4196b2bc98902b36de6de31a748d04b76770d228" - integrity sha512-z72wnEzSge6qTD9TUoUPp1A4j4jXk/MVii6rGE78XeE/Pq7HyyjU5bCagryMr9PC9MKa/oTiHcshKqWBDf57GA== +"@react-types/slider@^3.7.7": + version "3.7.7" + resolved "https://registry.yarnpkg.com/@react-types/slider/-/slider-3.7.7.tgz#f00450c6268665ff2ad38ad69bdf51d84ff2341a" + integrity sha512-lYTR9zXQV2fSEm/G3gwDENWiki1IXd/oorsgf0zu1DBi2SQDbOsLsGUXiwvD24Xy6OkUuhAqjLPPexezo7+u9g== dependencies: - "@react-types/shared" "^3.25.0" + "@react-types/shared" "^3.26.0" -"@react-types/switch@^3.5.6": - version "3.5.6" - resolved "https://registry.yarnpkg.com/@react-types/switch/-/switch-3.5.6.tgz#e18dcce0298ab52b70c9cdcdfe5e16224e7a248d" - integrity sha512-gJ8t2yTCgcitz4ON4ELcLLmtlDkn2MUjjfu3ez/cwA1X/NUluPYkhXj5Z6H+KOlnveqrKCZDRoTgK74cQ6Cvfg== +"@react-types/switch@^3.5.7": + version "3.5.7" + resolved "https://registry.yarnpkg.com/@react-types/switch/-/switch-3.5.7.tgz#f3fb589fce5819ca1c15f12479bf348e053adc27" + integrity sha512-1IKiq510rPTHumEZuhxuazuXBa2Cuxz6wBIlwf3NCVmgWEvU+uk1ETG0sH2yymjwCqhtJDKXi+qi9HSgPEDwAg== dependencies: - "@react-types/shared" "^3.25.0" + "@react-types/shared" "^3.26.0" -"@react-types/table@^3.10.2": - version "3.10.2" - resolved "https://registry.yarnpkg.com/@react-types/table/-/table-3.10.2.tgz#5e0be00eb61899ac6c9c322c6bad9cf94cbe157b" - integrity sha512-YzA4hcsYfnFFpA2UyGb1KKhLpWgaj5daApqjp126tCIosl8k1KxZmhKD50cwH0Jm19lALJseqo5VdlcJtcr4qg== +"@react-types/table@^3.10.3": + version "3.10.3" + resolved "https://registry.yarnpkg.com/@react-types/table/-/table-3.10.3.tgz#33959348641500e406abe330074f84b0c75ae4ac" + integrity sha512-Ac+W+m/zgRzlTU8Z2GEg26HkuJFswF9S6w26r+R3MHwr8z2duGPvv37XRtE1yf3dbpRBgHEAO141xqS2TqGwNg== dependencies: - "@react-types/grid" "^3.2.9" - "@react-types/shared" "^3.25.0" + "@react-types/grid" "^3.2.10" + "@react-types/shared" "^3.26.0" -"@react-types/tabs@^3.3.10": - version "3.3.10" - resolved "https://registry.yarnpkg.com/@react-types/tabs/-/tabs-3.3.10.tgz#98270b972b48e2272740391aaba033c620dec07e" - integrity sha512-s/Bw/HCIdWJPBw4O703ghKqhjGsIerRMIDxA88hbQYzfTDD6bkFDjCnsP2Tyy1G8Dg2rSPFUEE+k+PpLzqeEfQ== +"@react-types/tabs@^3.3.11": + version "3.3.11" + resolved "https://registry.yarnpkg.com/@react-types/tabs/-/tabs-3.3.11.tgz#b7db710ce2ca42a4e72cd2a581070212d2b07793" + integrity sha512-BjF2TqBhZaIcC4lc82R5pDJd1F7kstj1K0Nokhz99AGYn8C0ITdp6lR+DPVY9JZRxKgP9R2EKfWGI90Lo7NQdA== dependencies: - "@react-types/shared" "^3.25.0" + "@react-types/shared" "^3.26.0" -"@react-types/textfield@^3.9.7": - version "3.9.7" - resolved "https://registry.yarnpkg.com/@react-types/textfield/-/textfield-3.9.7.tgz#79b0bd2286dbf8ba39233279d1d7a3a3575ad553" - integrity sha512-vU5+QCOF9HgWGjAmmy+cpJibVW5voFomC5POmYHokm7kivYcMMjlonsgWwg/0xXrqE2qosH3tpz4jFoEuig1NQ== +"@react-types/textfield@^3.10.0": + version "3.10.0" + resolved "https://registry.yarnpkg.com/@react-types/textfield/-/textfield-3.10.0.tgz#10df39b75334174490a539ecae71ad19f5ea074d" + integrity sha512-ShU3d6kLJGQjPXccVFjM3KOXdj3uyhYROqH9YgSIEVxgA9W6LRflvk/IVBamD9pJYTPbwmVzuP0wQkTDupfZ1w== dependencies: - "@react-types/shared" "^3.25.0" + "@react-types/shared" "^3.26.0" -"@react-types/tooltip@^3.4.12": - version "3.4.12" - resolved "https://registry.yarnpkg.com/@react-types/tooltip/-/tooltip-3.4.12.tgz#70f5f1552a8c68fc21e5c400481c0f7fedc5ce30" - integrity sha512-FwsdSQ3UDIDORanQMGMLyzSUabw4AkKhwcRdPv4d5OT8GmJr7mBdZynfcsrKLJ0fzskIypMqspoutZidsI0MQg== +"@react-types/tooltip@^3.4.13": + version "3.4.13" + resolved "https://registry.yarnpkg.com/@react-types/tooltip/-/tooltip-3.4.13.tgz#f73fdc5c56790b7bd7c0d5382d0c758bd659e9d7" + integrity sha512-KPekFC17RTT8kZlk7ZYubueZnfsGTDOpLw7itzolKOXGddTXsrJGBzSB4Bb060PBVllaDO0MOrhPap8OmrIl1Q== dependencies: - "@react-types/overlays" "^3.8.10" - "@react-types/shared" "^3.25.0" + "@react-types/overlays" "^3.8.11" + "@react-types/shared" "^3.26.0" "@remix-run/router@1.19.0": version "1.19.0" From 6b3c9c99a139d1b0ab2d1bb2082be78cfa448d30 Mon Sep 17 00:00:00 2001 From: kaustubh-darekar Date: Mon, 2 Dec 2024 14:50:21 +0530 Subject: [PATCH 273/292] enable_communities flag removed in backend (#906) From 47a2db7b7cb55732f211b5d4a372da885f84cb6d Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Tue, 3 Dec 2024 10:09:22 +0000 Subject: [PATCH 274/292] added multimode metrics for json and fix for gemini ground truth metrics --- frontend/src/components/ChatBot/Chatbot.tsx | 13 ++++---- .../components/ChatBot/MetricsCheckbox.tsx | 5 ++- .../src/components/ChatBot/MetricsTab.tsx | 7 ++++- .../components/ChatBot/MultiModeMetrics.tsx | 31 ++++++++++++++++--- .../components/ChatBot/NotAvailableMetric.tsx | 20 ++++++++++++ .../Deduplication/index.tsx | 4 +-- .../SelectedJobList.tsx | 4 +-- frontend/src/utils/Constants.ts | 12 +++++++ frontend/src/utils/Utils.ts | 2 +- 9 files changed, 80 insertions(+), 18 deletions(-) create mode 100644 frontend/src/components/ChatBot/NotAvailableMetric.tsx diff --git a/frontend/src/components/ChatBot/Chatbot.tsx b/frontend/src/components/ChatBot/Chatbot.tsx index 8f2a72057..aa84764bc 100644 --- a/frontend/src/components/ChatBot/Chatbot.tsx +++ b/frontend/src/components/ChatBot/Chatbot.tsx @@ -249,7 +249,7 @@ const Chatbot: FC = (props) => { } else { setListMessages((prev) => prev.map((msg) => - msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg + (msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg) ) ); } @@ -264,7 +264,7 @@ const Chatbot: FC = (props) => { } else { setListMessages((prev) => prev.map((msg) => - msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg + (msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg) ) ); } @@ -273,7 +273,7 @@ const Chatbot: FC = (props) => { console.error(`API call failed for mode ${mode}:`, result.reason); setListMessages((prev) => prev.map((msg) => - msg.id === chatbotMessageId + (msg.id === chatbotMessageId ? { ...msg, modes: { @@ -281,7 +281,7 @@ const Chatbot: FC = (props) => { [mode]: { message: 'Failed to fetch response for this mode.', error: result.reason }, }, } - : msg + : msg) ) ); } @@ -294,7 +294,7 @@ const Chatbot: FC = (props) => { if (error instanceof Error) { setListMessages((prev) => prev.map((msg) => - msg.id === chatbotMessageId + (msg.id === chatbotMessageId ? { ...msg, isLoading: false, @@ -306,7 +306,7 @@ const Chatbot: FC = (props) => { }, }, } - : msg + : msg) ) ); } @@ -601,6 +601,7 @@ const Chatbot: FC = (props) => { nodes, tokensUsed, model, + multiModelMetrics, }, downloadLinkRef, 'graph-builder-chat-details.json' diff --git a/frontend/src/components/ChatBot/MetricsCheckbox.tsx b/frontend/src/components/ChatBot/MetricsCheckbox.tsx index 593468c2b..5b7fe89c0 100644 --- a/frontend/src/components/ChatBot/MetricsCheckbox.tsx +++ b/frontend/src/components/ChatBot/MetricsCheckbox.tsx @@ -3,13 +3,16 @@ import { Checkbox } from '@neo4j-ndl/react'; function MetricsCheckbox({ enableReference, toggleReferenceVisibility, + isDisabled = false, }: { enableReference: boolean; toggleReferenceVisibility: React.DispatchWithoutAction; + isDisabled?: boolean; }) { return ( diff --git a/frontend/src/components/ChatBot/MetricsTab.tsx b/frontend/src/components/ChatBot/MetricsTab.tsx index 33479eb13..b39292d94 100644 --- a/frontend/src/components/ChatBot/MetricsTab.tsx +++ b/frontend/src/components/ChatBot/MetricsTab.tsx @@ -12,6 +12,7 @@ import { capitalize } from '../../utils/Utils'; import { ThemeWrapperContext } from '../../context/ThemeWrapper'; import { InformationCircleIconOutline } from '@neo4j-ndl/react/icons'; import { metricsinfo } from '../../utils/Constants'; +import NotAvailableMetric from './NotAvailableMetric'; function MetricsTab({ metricsLoading, metricDetails, @@ -65,7 +66,11 @@ function MetricsTab({ columnHelper.accessor((row) => row.score as number, { id: 'Score', cell: (info) => { - return {info.getValue().toFixed(2)}; + const value = isNaN(info.getValue()) ? 'N.A' : info.getValue()?.toFixed(2); + if (value === 'N.A') { + return ; + } + return {value}; }, }), ], diff --git a/frontend/src/components/ChatBot/MultiModeMetrics.tsx b/frontend/src/components/ChatBot/MultiModeMetrics.tsx index c97d917b2..8bd89f1d8 100644 --- a/frontend/src/components/ChatBot/MultiModeMetrics.tsx +++ b/frontend/src/components/ChatBot/MultiModeMetrics.tsx @@ -11,6 +11,7 @@ import { Banner, Box, DataGrid, DataGridComponents, Flex, IconButton, Popover, T import { multimodelmetric } from '../../types'; import { ThemeWrapperContext } from '../../context/ThemeWrapper'; import { InformationCircleIconOutline } from '@neo4j-ndl/react/icons'; +import NotAvailableMetric from './NotAvailableMetric'; export default function MultiModeMetrics({ data, @@ -50,7 +51,11 @@ export default function MultiModeMetrics({ columnHelper.accessor((row) => row.answer_relevancy as number, { id: 'Answer Relevancy', cell: (info) => { - return {info.getValue().toFixed(2)}; + const value = isNaN(info.getValue()) ? 'N.A' : info.getValue()?.toFixed(2); + if (value === 'N.A') { + return ; + } + return {value}; }, header: () => ( @@ -73,7 +78,11 @@ export default function MultiModeMetrics({ columnHelper.accessor((row) => row.faithfulness as number, { id: 'Faithfullness', cell: (info) => { - return {info.getValue().toFixed(2)}; + const value = isNaN(info.getValue()) ? 'N.A' : info.getValue()?.toFixed(2); + if (value === 'N.A') { + return ; + } + return {value}; }, header: () => ( @@ -96,7 +105,11 @@ export default function MultiModeMetrics({ columnHelper.accessor((row) => row.context_entity_recall_score as number, { id: 'Entity Recall Score', cell: (info) => { - return {info.getValue()?.toFixed(2)}; + const value = isNaN(info.getValue()) ? 'N.A' : info.getValue()?.toFixed(2); + if (value === 'N.A') { + return ; + } + return {value}; }, header: () => ( @@ -119,7 +132,11 @@ export default function MultiModeMetrics({ columnHelper.accessor((row) => row.semantic_score as number, { id: 'Semantic Score', cell: (info) => { - return {info.getValue()?.toFixed(2)}; + const value = isNaN(info.getValue()) ? 'N.A' : info.getValue()?.toFixed(2); + if (value === 'N.A') { + return ; + } + return {value}; }, header: () => ( @@ -142,7 +159,11 @@ export default function MultiModeMetrics({ columnHelper.accessor((row) => row.rouge_score as number, { id: 'Rouge Score', cell: (info) => { - return {info.getValue()?.toFixed(2)}; + const value = isNaN(info.getValue()) ? 'N.A' : info.getValue()?.toFixed(2); + if (value === 'N.A') { + return ; + } + return {value}; }, header: () => ( diff --git a/frontend/src/components/ChatBot/NotAvailableMetric.tsx b/frontend/src/components/ChatBot/NotAvailableMetric.tsx new file mode 100644 index 000000000..f8df4c3c4 --- /dev/null +++ b/frontend/src/components/ChatBot/NotAvailableMetric.tsx @@ -0,0 +1,20 @@ +import { Flex, IconButton, Popover, Typography } from '@neo4j-ndl/react'; +import { InformationCircleIconOutline } from '@neo4j-ndl/react/icons'; + +export default function NotAvailableMetric() { + return ( + + N.A + + + + + + + + Some metrics are not available for Gemini model. + + + + ); +} diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx index df30c25c1..d59b46e21 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx @@ -104,12 +104,12 @@ export default function DeduplicationTab() { const onRemove = (nodeid: string, similarNodeId: string) => { setDuplicateNodes((prev) => { return prev.map((d) => - d.e.elementId === nodeid + (d.e.elementId === nodeid ? { ...d, similar: d.similar.filter((n) => n.elementId != similarNodeId), } - : d + : d) ); }); }; diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx index fc5f39206..447b1f846 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx @@ -11,11 +11,11 @@ export default function SelectedJobList({ }) { const ongoingPostProcessingTasks = useMemo( () => - isGdsActive + (isGdsActive ? postProcessingTasks.includes('enable_communities') ? postProcessingTasks : postProcessingTasks.filter((s) => s != 'enable_communities') - : postProcessingTasks.filter((s) => s != 'enable_communities'), + : postProcessingTasks.filter((s) => s != 'enable_communities')), [isGdsActive, postProcessingTasks] ); return ( diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index 7cf35f506..692d0faef 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -47,6 +47,18 @@ export const supportedLLmsForRagas = [ 'fireworks_llama_v3_70b', 'bedrock_claude_3_5_sonnet', ]; +export const supportedLLmsForGroundTruthMetrics = [ + 'openai_gpt_3.5', + 'openai_gpt_4', + 'openai_gpt_4o', + 'openai_gpt_4o_mini', + 'azure_ai_gpt_35', + 'azure_ai_gpt_4o', + 'groq_llama3_70b', + 'anthropic_claude_3_5_sonnet', + 'fireworks_llama_v3_70b', + 'bedrock_claude_3_5_sonnet', +]; export const prodllms = process.env.VITE_LLM_MODELS_PROD?.trim() != '' ? (process.env.VITE_LLM_MODELS_PROD?.split(',') as string[]) diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index 82217535d..7314c55e7 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -395,7 +395,7 @@ export const isFileCompleted = (waitingFile: CustomFile, item: SourceNode) => waitingFile && item.status === 'Completed'; export const calculateProcessedCount = (prev: number, batchSize: number) => - prev === batchSize ? batchSize - 1 : prev + 1; + (prev === batchSize ? batchSize - 1 : prev + 1); export const isProcessingFileValid = (item: SourceNode, userCredentials: UserCredentials) => { return item.status === 'Processing' && item.fileName != undefined && userCredentials && userCredentials.database; From 40ac6288cb2b2a9dacf9092e11a721de80142a5b Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Tue, 3 Dec 2024 17:49:47 +0530 Subject: [PATCH 275/292] Enhancement default model selection (#911) * LLM dropdown default value changes * merge dev * removing the stored default model --- frontend/src/components/Content.tsx | 5 +++-- frontend/src/components/Dropdown.tsx | 4 ++++ frontend/src/context/UsersFiles.tsx | 5 +++-- frontend/src/utils/Constants.ts | 5 ----- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 0f4d03c8c..932557dd3 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -13,7 +13,6 @@ import { batchSize, buttonCaptions, chatModeLables, - defaultLLM, largeFileSize, llms, RETRY_OPIONS, @@ -90,6 +89,7 @@ const Content: React.FC = ({ processedCount, setProcessedCount, setchatModes, + model } = useFileContext(); const [viewPoint, setViewPoint] = useState<'tableView' | 'showGraphView' | 'chatInfoView' | 'neighborView'>( 'tableView' @@ -537,6 +537,7 @@ const Content: React.FC = ({ setProcessedCount(0); setConnectionStatus(false); localStorage.removeItem('password'); + localStorage.removeItem('selectedModel') setUserCredentials({ uri: '', password: '', userName: '', database: '' }); setSelectedNodes([]); setSelectedRels([]); @@ -881,7 +882,7 @@ const Content: React.FC = ({ onSelect={handleDropdownChange} options={llms ?? ['']} placeholder='Select LLM Model' - defaultValue={defaultLLM} + defaultValue={model} view='ContentView' isDisabled={false} /> diff --git a/frontend/src/components/Dropdown.tsx b/frontend/src/components/Dropdown.tsx index a3ebd0d5a..2782addd9 100644 --- a/frontend/src/components/Dropdown.tsx +++ b/frontend/src/components/Dropdown.tsx @@ -17,6 +17,10 @@ const DropdownComponent: React.FC = ({ const isLargeDesktop = useMediaQuery(`(min-width:1440px )`); const handleChange = (selectedOption: OptionType | null | void) => { onSelect(selectedOption); + const existingModel = localStorage.getItem('selectedModel'); + if (existingModel != selectedOption?.value) { + localStorage.setItem('selectedModel', selectedOption?.value ?? ''); + } }; const allOptions = useMemo(() => options, [options]); return ( diff --git a/frontend/src/context/UsersFiles.tsx b/frontend/src/context/UsersFiles.tsx index 25f031f95..68bc50bdf 100644 --- a/frontend/src/context/UsersFiles.tsx +++ b/frontend/src/context/UsersFiles.tsx @@ -6,7 +6,7 @@ import { OptionType, showTextFromSchemaDialogType, } from '../types'; -import { chatModeLables, defaultLLM, getStoredSchema } from '../utils/Constants'; +import { chatModeLables, getStoredSchema, llms } from '../utils/Constants'; import { useCredentials } from './UserCredentials'; import Queue from '../utils/Queue'; @@ -16,13 +16,14 @@ const FileContextProvider: FC = ({ children }) => { const selectedNodeLabelstr = localStorage.getItem('selectedNodeLabels'); const selectedNodeRelsstr = localStorage.getItem('selectedRelationshipLabels'); const persistedQueue = localStorage.getItem('waitingQueue'); + const selectedModel = localStorage.getItem('selectedModel'); const { userCredentials } = useCredentials(); const [files, setFiles] = useState<(File | null)[] | []>([]); const [filesData, setFilesData] = useState([]); const [queue, setQueue] = useState( new Queue(JSON.parse(persistedQueue ?? JSON.stringify({ queue: [] })).queue) ); - const [model, setModel] = useState(defaultLLM); + const [model, setModel] = useState(selectedModel ?? llms[0]); const [graphType, setGraphType] = useState('Knowledge Graph Entities'); const [selectedNodes, setSelectedNodes] = useState([]); const [selectedRels, setSelectedRels] = useState([]); diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index 692d0faef..a80344209 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -28,11 +28,6 @@ export const llms = 'bedrock_claude_3_5_sonnet', ]; -export const defaultLLM = llms?.includes('openai_gpt_4o') - ? 'openai_gpt_4o' - : llms?.includes('gemini_1.5_pro') - ? 'gemini_1.5_pro' - : 'diffbot'; export const supportedLLmsForRagas = [ 'openai_gpt_3.5', 'openai_gpt_4', From 9d023a4c2631a0df89754d39709828db2ec5db22 Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Tue, 3 Dec 2024 17:57:57 +0530 Subject: [PATCH 276/292] Bug Fixing (#916) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Staging to main (#735) * Dev (#537) * format fixes and graph schema indication fix * Update README.md * added chat modes variable in env updated the readme * spell fix * added the chat mode in env table * added the logos * fixed the overflow issues * removed the extra fix * Fixed specific scenario "when the text from schema closes it should reopen the previous modal" * readme changes * removed dev console logs * added new retrieval query (#533) * format fixes and tab rendering fix * fixed the setting modal reopen issue --------- Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * disabled the sumbit buttom on loading * Deduplication tab (#566) * de-duplication API * Update De-Duplicate query * created the Deduplication tab * added the API service * added the removeable tags for similar nodes in deduplication tab * Integrate Tag * added GraphLabel * added loader state * added the merge service * integrated the merge API * Merge Query issue fixed * Auto refresh the duplicate nodes after merging operation * added the description for de duplication * reset on merging --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Update frontend_docs.adoc (#538) * Update frontend_docs.adoc * doc update * Images * Images folder change * Images folder change * test image * Update frontend_docs.adoc * image change * Update frontend_docs.adoc * Update frontend_docs.adoc * added the Graph Mode SS * added the Query SS * Update frontend_docs.adoc * conflics fix * conflict fix * Update frontend_docs.adoc --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * updated langchain versions (#565) * Update the De-Duplication query * Node relationship id type none issue (#547) * de-duplication API * Update De-Duplicate query * Issue fixed Nodes,Relationship Id and Type None or Blank * added the tooltips * type fix * Unneccory import * added score threshold and added some error handling (#571) * Update requirements.txt * Tooltip and other UI fixes (#572) * Staging To Main (#495) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * Dev (#433) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env * DEV to STAGING (#461) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * DEV to STAGING (#462) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * added upload api * changed the dropzone error message * Dev to staging (#466) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env * added upload api * changed the dropzone error message --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-auth… * Update FileTable.tsx * merge changes * Update README.md * Update README.md * Update README.md * Update README.md * Graph visualization improvement and chunk text details (#860) * Update README.md * Dev to staging (#859) * processing count updated on cancel * format fixes * remove whitespace for enviroment variable which due to an error "xxx may not contain whitespace" (#707) * updated disconnected nodes * updated disconnected nodes * fix: Processed count update on failed condition * added disconnected and up nodes * removed __Entity__ labels * removed graph_object * removed graph object in the function * resetting the alert message on success scenario * Modified queries * populate graph schema * not clearing the password when there is error scenario * fixed the vector index loading issue * fix: empty credentials payload for recreate vector index api * chatbot status (#676) * chatbot status * connection status check for ASK button * refresh disable check * review comment resolved * format fixes * added properties and modified to entity labels * Post processing call after all files completion (#716) * Dev To STAGING (#532) * format fixes and graph schema indication fix * Update README.md * added chat modes variable in env updated the readme * spell fix * added the chat mode in env table * added the logos * fixed the overflow issues * removed the extra fix * Fixed specific scenario "when the text from schema closes it should reopen the previous modal" * readme changes * removed dev console logs * added new retrieval query (#533) * format fixes and tab rendering fix * fixed the setting modal reopen issue --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Dev (#535) * format fixes and graph schema indication fix * Update README.md * added chat modes variable in env updated the readme * spell fix * added the chat mode in env table * added the logos * fixed the overflow issues * removed the extra fix * Fixed specific scenario "when the text from schema closes it should reopen the previous modal" * readme changes * removed dev console logs * added new retrieval query (#533) * format fixes and tab rendering fix * fixed the setting modal reopen issue --------- Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Dev (#537) * format fixes and graph schema indication fix * Update README.md * added chat modes variable in env updated the readme * spell fix * added the chat mode in env table * added the logos * fixed the overflow issues * removed the extra fix * Fixed specific scenario "when the text from schema closes it should reopen the previous modal" * readme changes * removed dev console logs * added new retrieval query (#533) * format fixes and tab rendering fix * fixed the setting modal reopen issue --------- Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> * Fix typo: correct 'josn_obj' to 'json_obj' (#697) * Staging To Main (#495) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * Dev (#433) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env * DEV to STAGING (#461) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * DEV to STAGING (#462) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * format fixes * removed unused import * added the capitalize method * delete files from merged_file_path only if source is local file --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * commented total page code (#460) * format fixes * removed the disabled check on dropdown * Large file env --------- Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> * added upload api * changed the dropzone error message * Dev to staging (#466) * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * recent merges * pdf deletion due to out of diskspace * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * Convert is_cancelled value from string to bool * added the default page size * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * offset in chunks (#389) * page number in gcs loader (#393) * added youtube timestamps (#392) * chat pop up button (#387) * expand * minimize-icon * css changes * chat history * chatbot wider Side Nav * expand icon * chatbot UI * Delete * merge fixes * code suggestions --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * chunks create before extraction using is_pre_process variable (#383) * chunks create before extraction using is_pre_process variable * Return total pages for Model * update requirement.txt * total pages on uplaod API * added the Confirmation Dialog * added the selected files into the confirmation modal * format and lint fixes * added the stop watch image * fileselection on alert dialog * Add timeout in docker for gunicorn workers * Add cancel icon to info popup (#384) * Info Modal Changes * css changes * recent merges * Integration_qa test (#375) * Test IntegrationQA added * update test cases * update test * update node count assertions * test changes * update changes * modification test * Code refatctor test cases * Handle allowedlist issue in test * test changes * update test * test case execution * test chatbot updates * test case update file * added file --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * fixed status blank issue * Rendering the file name instead of link for gcs and s3 sources in the info modal * added the default page size * Convert is_cancelled value from string to bool * Issue fixed Processed chunked as 0 when file re-process again * Youtube timestamps (#386) * Wikipedia source to accept all valid urls * wikipedia url to support multiple languages * integrated wiki langauge param for extract api * Youtube video timestamps --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * groq llm integration backend (#286) * groq llm integration backend * groq and description in node properties * added groq in options --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Save Total Pages in DB * Added total Pages * file selection when we didn't select anything from Main table * added the danger icon only for large files * added the overflow for more files and file selection for all new files * moved the interface to types * added the icon accoroding to the source * set total page for wiki and youtube * h3 heading * merge * updated the alert on basis if total pages * deleted chunks * polling based on total pages * isNan check * large file based on file size for s3 and gcs * file source in server side event * time calculation based on chunks for gcs and s3 --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * fixed the layout issue * Populate graph schema (#399) * crreate new endpoint populate_graph_schema and update the query for getting lables from DB * Added main.py changes * conditionally-including-the-gcs-login-flow-in-gcs-as-source (#396) * added the condtion * removed llms * Fixed issue : Remove extra unused param * get emb only if used (#278) * Chatbot chunks (#402) * Added file name to the content sent to LLM * added chunk text in the response * increased the docs parts sent to llm * Modified graph query * mardown rendering * youtube starttime * icons * offset changes * removed the files due to codespace space issue --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user (#405) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * fixed css issue * fixed status blank issue * Modified response when no docs is retrived (#413) * Fixed env/docker-compose for local deployments + README doc (#410) * Fixed env/docker-compose for local deployments + README doc * wrong place for ENV in README * by default, removed langsmith + fixed knn score string to float * by default, removed langsmith + fixed knn score string to float * Fixed strings in docker-compose env * Added requirements (neo4j 5.15 or later, APOC, and instructions for Neo4j Desktop) * Missed the TIME_PER_PAGE env, was causing NaN issue in the approx time processing notification. fixed that * Support for all unstructured files (#401) * all unstructured files * responsiveness * added file type * added the extensions * spell mistake * ppt file changes --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Settings modal to support generating the labels from the llm by using text given by user with checkbox (#415) * added the json * added schema from text dialog * integrated the schemaAPI * added the alert * resize fixes * Extract schema using direct ChatOpenAI API and Chain * integrated the checkbox for schema to text dialog * Update SettingModal.tsx --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * gcs file content read via storage client (#417) * gcs file content read via storage client * added the access token the file state --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * pypdf2 to read files from gcs (#420) * 407 remove driver from frontend (#416) * removed driver * removed API * connecting to database on page refresh --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Css handling of info modal and Tooltips (#418) * css change * toolTips * Sidebar Tooltips * copy to clip * css change * added image types * added gcs * type fix * docker changes * speech * added the toolip for dropzone sources --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed retrival bugs (#421) * yarn format fixes * changed the delete message * added the cancel button * changed the message on tooltip * added space * UI fixes * tooltip for setting * updated req * wikipedia URL input (#424) * accept only wikipedia links * added wikipedia link * added wikilink regex * wikipedia single url only * changed the alert message * wording change * pushed validation state persist error --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * speech and copy (#422) * speech and copy * startTime * added chunk properties * tooltips --------- Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * Fixed issue for out of range in KNN API * solved conflicts * conflict solved * Remove logging info from update KNN API * tooltip changes * format and lint fixes * responsiveness changes * Fixed issue for total pages GCS, S3 * UI polishing (#428) * button and tooltip changes * checking validation on change * settings module populate fix * format fixes * opening the modal after auth success * removed the limit * added the scrobar for dropdowns * speech state (#426) * speech state * Button Details changes * delete wording change * Total pages in buckets (#431) * page number NA for buckets * added N/A for gcs and s3 pages * total pages for gcs * remove unwanted logger --------- Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> * removed the max width * Update FileTable.tsx * Update the docker file * Modified prompt (#438) * Update Dockerfile * Update Dockerfile * Update Dockerfile * rendering Fix * Local file upload gcs (#442) * Uplaod file to GCS * GCS local upload fixed issue and delete file from GCS after processing and failed or cancelled * Add life cycle rule on uploaded bucket * pdf upload local and gcs bucket check * delete files when processed and extract changes --------- Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> * Modified chat length and entities used (#443) * metadata for unstructured files (#446) * Unstructured file metadata (#447) * metadata for unstructured files * sleep in gcs upload * updated * icons added to chunks (#435) * icons added to chunks * info modal icons * fixed gcs status message issue * added if check for failed count * Null issue Fixed from backend for upload API and graph_document when model name mismatch * added word break issue * Added neo4j-rust-ext * processing time estimation based on bytes * File extension upper case fixed, File delete from GCS or local based on env variable. * timer per byte * Update Dockerfile * Adding sort rows on the table (#451) * Gcs upload folder hashed (#453) * implement foldername hashed in GCS bucket uplaod * Raise exception if invalid model selected * folder name for gcs upload --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> * upload all unstructuredfiles to gcs (#455) * Mofified chunk query (#454) * Added libre office for fixing error -- soffice command was not found. Please install libreoffice on your system and try again. - Install instructions: https://www.libreoffice.org/get-help/install-howto/ - Mac: https://formulae.brew.sh/cask/libreoffice - Debian: https://wiki.debian.org/LibreOffice" * Fix the PARTIAL CONTENT issue * File-table no data found (#456) * 'file-table'' * review comment * Llm format change (#459) * changed the llm models format to lowercase * added the error message * llm model changes * for… * enable communities removed and delete queries updated * nginx security headers * removed parameter to include chunk nodes as entity source * Ready to reprocess * communities fix * dependency fix Reprocess fix * icon size fix * z index fix * icon fix * icon gap fix * upload status * Checkbox fix * fix: table issue chat bot clear issue * new document deletion, 2nd level community deletion handled * claer history * graph info and delete query update * format changes * refresh changes * refresh changes * chat history changes * code refactor --------- Co-authored-by: aashipandya <156318202+aashipandya@users.noreply.github.com> Co-authored-by: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Co-authored-by: vasanthasaikalluri <165021735+vasanthasaikalluri@users.noreply.github.com> Co-authored-by: Pravesh Kumar <121786590+praveshkumar1988@users.noreply.github.com> Co-authored-by: karanchellani <142801957+karanchellani@users.noreply.github.com> Co-authored-by: abhishekkumar-27 <164544129+abhishekkumar-27@users.noreply.github.com> Co-authored-by: Ajay Meena Co-authored-by: Morgan Senechal Co-authored-by: Ikko Eltociear Ashimine Co-authored-by: Jayanth T Co-authored-by: Jayanth T Co-authored-by: Jerome Choo Co-authored-by: jeromechoo Co-authored-by: Michael Hunger Co-authored-by: Kain Shu <44948284+Kain-90@users.noreply.github.com> Co-authored-by: destiny966113 <90891243+destiny966113@users.noreply.github.com> Co-authored-by: Pravesh1988 Co-authored-by: edenbuaa Co-authored-by: kaustubh-darekar Co-authored-by: a-s-poorna --- frontend/src/components/ChatBot/Chatbot.tsx | 12 +- .../src/components/Graph/GraphViewModal.tsx | 32 ++--- frontend/src/components/Layout/PageLayout.tsx | 116 ++++++++---------- .../Deduplication/index.tsx | 4 +- .../SelectedJobList.tsx | 4 +- frontend/src/utils/Constants.ts | 2 +- frontend/src/utils/Utils.ts | 2 +- 7 files changed, 81 insertions(+), 91 deletions(-) diff --git a/frontend/src/components/ChatBot/Chatbot.tsx b/frontend/src/components/ChatBot/Chatbot.tsx index aa84764bc..877dcdab4 100644 --- a/frontend/src/components/ChatBot/Chatbot.tsx +++ b/frontend/src/components/ChatBot/Chatbot.tsx @@ -249,7 +249,7 @@ const Chatbot: FC = (props) => { } else { setListMessages((prev) => prev.map((msg) => - (msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg) + msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg ) ); } @@ -264,7 +264,7 @@ const Chatbot: FC = (props) => { } else { setListMessages((prev) => prev.map((msg) => - (msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg) + msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg ) ); } @@ -273,7 +273,7 @@ const Chatbot: FC = (props) => { console.error(`API call failed for mode ${mode}:`, result.reason); setListMessages((prev) => prev.map((msg) => - (msg.id === chatbotMessageId + msg.id === chatbotMessageId ? { ...msg, modes: { @@ -281,7 +281,7 @@ const Chatbot: FC = (props) => { [mode]: { message: 'Failed to fetch response for this mode.', error: result.reason }, }, } - : msg) + : msg ) ); } @@ -294,7 +294,7 @@ const Chatbot: FC = (props) => { if (error instanceof Error) { setListMessages((prev) => prev.map((msg) => - (msg.id === chatbotMessageId + msg.id === chatbotMessageId ? { ...msg, isLoading: false, @@ -306,7 +306,7 @@ const Chatbot: FC = (props) => { }, }, } - : msg) + : msg ) ); } diff --git a/frontend/src/components/Graph/GraphViewModal.tsx b/frontend/src/components/Graph/GraphViewModal.tsx index 27610680d..b93cf4b98 100644 --- a/frontend/src/components/Graph/GraphViewModal.tsx +++ b/frontend/src/components/Graph/GraphViewModal.tsx @@ -58,15 +58,16 @@ const GraphViewModal: React.FunctionComponent = ({ const [graphType, setGraphType] = useState([]); const [disableRefresh, setDisableRefresh] = useState(false); const [selected, setSelected] = useState<{ type: EntityType; id: string } | undefined>(undefined); + const [mode, setMode] = useState(false); const graphQuery: string = graphType.includes('DocumentChunk') && graphType.includes('Entities') ? queryMap.DocChunkEntities : graphType.includes('DocumentChunk') - ? queryMap.DocChunks - : graphType.includes('Entities') - ? queryMap.Entities - : ''; + ? queryMap.DocChunks + : graphType.includes('Entities') + ? queryMap.Entities + : ''; // fit graph to original position const handleZoomToFit = () => { @@ -97,7 +98,12 @@ const GraphViewModal: React.FunctionComponent = ({ }, []); useEffect(() => { - const updateGraphType = graphTypeFromNodes(allNodes); + let updateGraphType; + if (mode) { + updateGraphType = graphTypeFromNodes(nodes); + } else { + updateGraphType = graphTypeFromNodes(allNodes); + } if (Array.isArray(updateGraphType)) { setGraphType(updateGraphType); } @@ -108,10 +114,10 @@ const GraphViewModal: React.FunctionComponent = ({ const nodeRelationshipData = viewPoint === graphLabels.showGraphView ? await graphQueryAPI( - userCredentials as UserCredentials, - graphQuery, - selectedRows?.map((f) => f.name) - ) + userCredentials as UserCredentials, + graphQuery, + selectedRows?.map((f) => f.name) + ) : await graphQueryAPI(userCredentials as UserCredentials, graphQuery, [inspectedName ?? '']); return nodeRelationshipData; } catch (error: any) { @@ -260,11 +266,10 @@ const GraphViewModal: React.FunctionComponent = ({ const newGraphSelected = [...graphType]; if (currentIndex === -1) { newGraphSelected.push(graph); - initGraph(newGraphSelected, allNodes, allRelationships, scheme); } else { newGraphSelected.splice(currentIndex, 1); - initGraph(newGraphSelected, allNodes, allRelationships, scheme); } + initGraph(newGraphSelected, allNodes, allRelationships, scheme); setSearchQuery(''); setGraphType(newGraphSelected); setSelected(undefined); @@ -295,11 +300,8 @@ const GraphViewModal: React.FunctionComponent = ({ // Refresh the graph with nodes and relations if file is processing const handleRefresh = () => { setDisableRefresh(true); + setMode(true); graphApi('refreshMode'); - setGraphType(graphType); - setNodes(nodes); - setRelationships(relationships); - setScheme(newScheme); }; // when modal closes reset all states to default diff --git a/frontend/src/components/Layout/PageLayout.tsx b/frontend/src/components/Layout/PageLayout.tsx index dca910e43..71908bc64 100644 --- a/frontend/src/components/Layout/PageLayout.tsx +++ b/frontend/src/components/Layout/PageLayout.tsx @@ -14,14 +14,12 @@ import useSpeechSynthesis from '../../hooks/useSpeech'; import FallBackDialog from '../UI/FallBackDialog'; import { envConnectionAPI } from '../../services/ConnectAPI'; import { healthStatus } from '../../services/HealthStatus'; +import { useNavigate } from 'react-router'; const ConnectionModal = lazy(() => import('../Popups/ConnectionModal/ConnectionModal')); -interface PageLayoutProp { - isChatOnly?: boolean; -} -const PageLayout: React.FC = () => { +const PageLayout: React.FC = () => { const [openConnection, setOpenConnection] = useState({ openPopUp: false, chunksExists: false, @@ -38,6 +36,8 @@ const PageLayout: React.FC = () => { const [shows3Modal, toggleS3Modal] = useReducer((s) => !s, false); const [showGCSModal, toggleGCSModal] = useReducer((s) => !s, false); const [showGenericModal, toggleGenericModal] = useReducer((s) => !s, false); + const navigate = useNavigate(); + const toggleLeftDrawer = () => { if (largedesktops) { setIsLeftExpanded(!isLeftExpanded); @@ -87,6 +87,7 @@ const PageLayout: React.FC = () => { const setUserCredentialsFromSession = (neo4jConnection: string) => { if (!neo4jConnection) { console.error('Invalid session data:', neo4jConnection); + setOpenConnection((prev) => ({ ...prev, openPopUp: true })); return; } try { @@ -138,21 +139,21 @@ const PageLayout: React.FC = () => { return false; } }; + // Handle case where session exists + let backendApiResponse; try { - // Handle case where session exists - if (session && isDev) { - let backendApiResponse; - try { - backendApiResponse = await envConnectionAPI(); - const connectionData = backendApiResponse.data; - const envCredentials = { - uri: connectionData.data.uri, - password: atob(connectionData.data.password), - userName: connectionData.data.user_name, - database: connectionData.data.database, - isReadonlyUser: !connectionData.data.write_access, - isGds: connectionData.data.gds_status, - }; + if (isDev) { + backendApiResponse = await envConnectionAPI(); + const connectionData = backendApiResponse.data; + const envCredentials = { + uri: connectionData.data.uri, + password: atob(connectionData.data.password), + userName: connectionData.data.user_name, + database: connectionData.data.database, + isReadonlyUser: !connectionData.data.write_access, + isGds: connectionData.data.gds_status, + }; + if (session && isDev) { const updated = updateSessionIfNeeded(envCredentials, session); if (!updated) { setUserCredentialsFromSession(session); // Using stored session if no update is needed @@ -160,65 +161,51 @@ const PageLayout: React.FC = () => { setConnectionStatus(Boolean(connectionData.data.graph_connection)); setIsBackendConnected(true); handleDisconnectButtonState(false); - } catch (error) { - console.error('Error in DEV session handling:', error); - handleDisconnectButtonState(true); - setOpenConnection((prev) => ({ ...prev, openPopUp: true })); - setErrorMessage(backendApiResponse?.data.error); } - } else { - // For PROD, picking the session values - setUserCredentialsFromSession(session as string); - setConnectionStatus(true); - setIsBackendConnected(true); - handleDisconnectButtonState(true); - return; - } - // Handle case where no session exists - if (isDev) { - let envAPiResponse; - try { - envAPiResponse = await envConnectionAPI(); - const connectionData = envAPiResponse.data.data; - const credentials = { - uri: connectionData.uri, - password: atob(connectionData.password), - userName: connectionData.user_name, - database: connectionData.database, - isReadonlyUser: !connectionData.write_access, - isGds: connectionData.gds_status, - }; - setUserCredentials(credentials); + else if (!session) { + setUserCredentials(envCredentials); localStorage.setItem( 'neo4j.connection', JSON.stringify({ - uri: credentials.uri, - user: credentials.userName, - password: btoa(credentials.password), - database: credentials.database, + uri: envCredentials.uri, + user: envCredentials.userName, + password: btoa(envCredentials.password), + database: envCredentials.database, userDbVectorIndex: 384, - isReadOnlyUser: credentials.isReadonlyUser, - isGDS: credentials.isGds, + isReadOnlyUser: envCredentials.isReadonlyUser, + isGDS: envCredentials.isGds, }) ); - setConnectionStatus(Boolean(connectionData.graph_connection)); - setIsBackendConnected(true); + setConnectionStatus(true); + setGdsActive(envCredentials.isGds); + setIsReadOnlyUser(envCredentials.isReadonlyUser); handleDisconnectButtonState(false); - } catch (error) { - console.error('Error in DEV no-session handling:', error); + } + } + else { + if (session && !isDev) { + // For PROD, picking the session values + setUserCredentialsFromSession(session as string); + setConnectionStatus(true); handleDisconnectButtonState(true); + return; + } + else { setOpenConnection((prev) => ({ ...prev, openPopUp: true })); - setErrorMessage(envAPiResponse?.data.error); + handleDisconnectButtonState(true); } - } else { - // For PROD: Open modal to manually connect - handleDisconnectButtonState(true); - setOpenConnection((prev) => ({ ...prev, openPopUp: true })); - setIsBackendConnected(false); } } catch (error) { - console.error('Error in initializeConnection:', error); - setIsBackendConnected(false); + console.error('Error in DEV session handling:', error); + if (session) { + setUserCredentialsFromSession(session as string); + setConnectionStatus(true); + } + else { + setErrorMessage(backendApiResponse?.data.error); + setOpenConnection((prev) => ({ ...prev, openPopUp: true })); + } + handleDisconnectButtonState(true); } } initializeConnection(); @@ -249,6 +236,7 @@ const PageLayout: React.FC = () => { currentMode: 'graph+vector+fulltext', }, ]); + navigate('.', { replace: true, state: null }); } } catch (error) { console.log(error); diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx index d59b46e21..df30c25c1 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx @@ -104,12 +104,12 @@ export default function DeduplicationTab() { const onRemove = (nodeid: string, similarNodeId: string) => { setDuplicateNodes((prev) => { return prev.map((d) => - (d.e.elementId === nodeid + d.e.elementId === nodeid ? { ...d, similar: d.similar.filter((n) => n.elementId != similarNodeId), } - : d) + : d ); }); }; diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx index 447b1f846..fc5f39206 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx @@ -11,11 +11,11 @@ export default function SelectedJobList({ }) { const ongoingPostProcessingTasks = useMemo( () => - (isGdsActive + isGdsActive ? postProcessingTasks.includes('enable_communities') ? postProcessingTasks : postProcessingTasks.filter((s) => s != 'enable_communities') - : postProcessingTasks.filter((s) => s != 'enable_communities')), + : postProcessingTasks.filter((s) => s != 'enable_communities'), [isGdsActive, postProcessingTasks] ); return ( diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index a80344209..6044cb748 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -302,7 +302,7 @@ export const graphLabels = { community: 'Communities', noNodesRels: 'No Nodes and No relationships', neighborView: 'neighborView', - chunksInfo: 'We are processing 50 chunks at a time', + chunksInfo: 'We are visualizing 50 chunks at a time', }; export const RESULT_STEP_SIZE = 25; diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index 7314c55e7..82217535d 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -395,7 +395,7 @@ export const isFileCompleted = (waitingFile: CustomFile, item: SourceNode) => waitingFile && item.status === 'Completed'; export const calculateProcessedCount = (prev: number, batchSize: number) => - (prev === batchSize ? batchSize - 1 : prev + 1); + prev === batchSize ? batchSize - 1 : prev + 1; export const isProcessingFileValid = (item: SourceNode, userCredentials: UserCredentials) => { return item.status === 'Processing' && item.fileName != undefined && userCredentials && userCredentials.database; From b85d31e5a8d67fad3de715ad7617540b99efd1ca Mon Sep 17 00:00:00 2001 From: kaustubh-darekar Date: Tue, 3 Dec 2024 18:05:33 +0530 Subject: [PATCH 277/292] Update documentation (#915) * Update backend_docs.adoc Documents updated for v6 * Update example.env --- backend/example.env | 1 + docs/backend/backend_docs.adoc | 73 ++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/backend/example.env b/backend/example.env index 7fa3cb480..7cf9b13ac 100644 --- a/backend/example.env +++ b/backend/example.env @@ -31,6 +31,7 @@ DUPLICATE_TEXT_DISTANCE = "" #examples LLM_MODEL_CONFIG_openai_gpt_3.5="gpt-3.5-turbo-0125,openai_api_key" LLM_MODEL_CONFIG_openai_gpt_4o_mini="gpt-4o-mini-2024-07-18,openai_api_key" +LLM_MODEL_CONFIG_openai_gpt_4o="gpt-4o-2024-11-20,openai_api_key" LLM_MODEL_CONFIG_gemini_1.5_pro="gemini-1.5-pro-002" LLM_MODEL_CONFIG_gemini_1.5_flash="gemini-1.5-flash-002" LLM_MODEL_CONFIG_diffbot="diffbot,diffbot_api_key" diff --git a/docs/backend/backend_docs.adoc b/docs/backend/backend_docs.adoc index 7f1fd11dc..058f88a58 100644 --- a/docs/backend/backend_docs.adoc +++ b/docs/backend/backend_docs.adoc @@ -978,6 +978,79 @@ The API responsible for a evaluating chatbot responses on the basis of different } } } +.... + +=== Evaluate response with ground truth +---- +POST /additional_metrics +---- + +The API responsible for a evaluating chatbot responses on the basis of different metrics such as context entity recall, semantic score, rouge score. This reuqire additional ground truth to be supplied by user. This utilises RAGAS library to calculate these metrics. + +**API Parameters :** + +* `question`= User query for the chatbot +* `context`= context retrieved by retrieval mode used for answer generation +* `answer`= answer generated by chatbot +* `reference`= ground truth/ expected answer provided by user +* `model`= LLM model +* `mode`= Retrieval mode used for answer generationRetrieval mode used for answer generation + +**Response :** +[source,json,indent=0] +.... +{ + "status": "Success", + "data": { + "graph_vector_fulltext": { + "rouge_score": 1.0, + "semantic_score": 0.9842, + "context_entity_recall_score": 0.5 + } + } +} +.... + +=== Fetch chunk text + +---- +POST /fetch_chunktext +---- + +The API responsible for a fetching text associated with a particular chunk and chunk metadata. + +**API Parameters :** + +* `uri`=Neo4j uri, +* `userName`= Neo4j db username, +* `password`= Neo4j db password, +* `database`= Neo4j database name +* `document_name` = Name of document for which chunks needs to be fetched. +* `page no` = page number for multipage + +**Response :** +[source,json,indent=0] +.... +{ + "status": "Success", + "data": { + "pageitems": [ + { + "text": "By T. Albert Illustrated by: maaillustrations.com Science has never been so much fun. Here is all that a child needs to know about water, rain, hail, sleet and water cycle. When Professor Mois Ture teaches- little readers read, learn and ask for more….. Published by Monkey Pen Ltd Dear Supporter, Thank you for downloading our childrens books. Monkey Pens Vision is to provide thousands of free childrens books to young readers around the globe. Please share our books with your friends and family to support our mission. Thank you Please make a donation on Patreon to support Monkey Pens Free Book Project: Hi, I am Professor Mois Ture and I will be telling you about water. You can call it RAIN. You can call it SNOW. You can call it SLEET. You can call it HAIL. But it’s WATER all the same. Did you ever wonder how", + "position": 1, + "pagenumber": 1 + }, + { + "text": " it HAIL. But it’s WATER all the same. Did you ever wonder how old water is or where it comes from? The answers may surprise you. The next time you see a pond or even a glass of water, think about how old that water might be. Do you really want to know ? I thought you did. Did you brush your teeth this morning? Well, some of the water that you used could have fallen from the sky yesterday, or a week, or month ago. It’s pretty new. But, some part of that water is very old and was around during the time of the dinosaurs, or even longer. Or maybe it’s a little newer; like from the time when the Pharaohs were building pyramids. You see there is only a limited amount of water and it gets recycled. Yep! It keeps going round and round. We call it the “Water Cycle.” Yes – You", + "position": 2, + "pagenumber": 2 + } + ], + "total_pages": 1 + }, + "message": "Total elapsed API time 0.48" +} + .... === Backend Database connection ---- From 978409094a3975df4a3c4cc1e036f4ffa2a37934 Mon Sep 17 00:00:00 2001 From: kaustubh-darekar Date: Tue, 3 Dec 2024 19:49:20 +0530 Subject: [PATCH 278/292] Updating langchain-neo4j package (#891) * Adding langchain-Neo4j package in application * langchain neo4j package updated, requirement.txt file updated with only necessary packages and their latest versions. unnecessary imports removed. * refactored code. replaced print statements with logging info * Updated sentence transformer to huggingface embeddings --- backend/requirements.txt | 206 ++++----------------- backend/score.py | 6 +- backend/src/QA_integration.py | 11 +- backend/src/create_chunks.py | 4 +- backend/src/diffbot_transformer.py | 3 +- backend/src/document_sources/gcs_bucket.py | 5 +- backend/src/document_sources/local_file.py | 2 - backend/src/document_sources/youtube.py | 37 ---- backend/src/graphDB_dataAccess.py | 7 +- backend/src/graph_query.py | 2 - backend/src/llm.py | 19 -- backend/src/main.py | 49 ++--- backend/src/make_relationships.py | 2 +- backend/src/post_processing.py | 2 +- backend/src/ragas_eval.py | 5 +- backend/src/shared/common_fn.py | 18 +- 16 files changed, 71 insertions(+), 307 deletions(-) diff --git a/backend/requirements.txt b/backend/requirements.txt index 5f0f5dc62..de1fc1136 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -1,183 +1,57 @@ -aiohttp==3.9.3 -aiosignal==1.3.1 -annotated-types==0.6.0 -antlr4-python3-runtime==4.9.3 -anyio==4.3.0 -async-timeout==4.0.3 asyncio==3.4.3 -attrs==23.2.0 -backoff==2.2.1 -beautifulsoup4==4.12.3 -boto3==1.34.140 -botocore==1.34.140 -cachetools==5.3.3 -certifi==2024.2.2 -cffi==1.16.0 -chardet==5.2.0 -charset-normalizer==3.3.2 -click==8.1.7 -coloredlogs==15.0.1 -contourpy==1.2.0 -cryptography==42.0.2 -cycler==0.12.1 -dataclasses-json==0.6.4 -dataclasses-json-speakeasy==0.5.11 -Deprecated==1.2.14 -distro==1.9.0 -docstring_parser==0.16 -effdet==0.4.1 -emoji==2.10.1 -exceptiongroup==1.2.0 -fastapi==0.111.0 +boto3==1.35.69 +botocore==1.35.69 +certifi==2024.8.30 +fastapi==0.115.5 fastapi-health==0.4.0 -filelock==3.13.1 -filetype==1.2.0 -flatbuffers==23.5.26 -fonttools==4.49.0 -frozenlist==1.4.1 -fsspec==2024.2.0 -google-api-core==2.18.0 -google-auth==2.29.0 -google_auth_oauthlib==1.2.0 -google-cloud-aiplatform==1.58.0 -google-cloud-bigquery==3.19.0 +google-api-core==2.23.0 +google-auth==2.36.0 +google_auth_oauthlib==1.2.1 google-cloud-core==2.4.1 -google-cloud-resource-manager==1.12.3 -google-cloud-storage==2.17.0 -google-crc32c==1.5.0 -google-resumable-media==2.7.0 -googleapis-common-protos==1.63.0 -greenlet==3.0.3 -grpc-google-iam-v1==0.13.0 -grpcio==1.62.1 -google-ai-generativelanguage==0.6.6 -grpcio-status==1.62.1 -h11==0.14.0 -httpcore==1.0.4 -httpx==0.27.0 -huggingface-hub -humanfriendly==10.0 -idna==3.6 -importlib-resources==6.1.1 +json-repair==0.30.2 pip-install==1.3.5 -iopath==0.1.10 -Jinja2==3.1.3 -jmespath==1.0.1 -joblib==1.3.2 -jsonpatch==1.33 -jsonpath-python==1.0.6 -jsonpointer==2.4 -json-repair==0.25.2 -kiwisolver==1.4.5 -langchain==0.3.0 -langchain-aws==0.2.1 -langchain-anthropic==0.2.1 -langchain-fireworks==0.2.0 -langchain-google-genai==2.0.0 -langchain-community==0.3.0 -langchain-core==0.3.5 -langchain-experimental==0.3.1 -langchain-google-vertexai==2.0.1 -langchain-groq==0.2.0 -langchain-openai==0.2.0 -langchain-text-splitters==0.3.0 +langchain==0.3.8 +langchain-aws==0.2.7 +langchain-anthropic==0.3.0 +langchain-fireworks==0.2.5 +langchain-community==0.3.8 +langchain-core==0.3.21 +langchain-experimental==0.3.3 +langchain-google-vertexai==2.0.7 +langchain-groq==0.2.1 +langchain-openai==0.2.9 +langchain-text-splitters==0.3.2 +langchain-huggingface==0.1.2 langdetect==1.0.9 -langsmith==0.1.128 -layoutparser==0.3.4 +langsmith==0.1.146 langserve==0.3.0 -#langchain-cli==0.0.25 -lxml==5.1.0 -MarkupSafe==2.1.5 -marshmallow==3.20.2 -matplotlib==3.7.2 -mpmath==1.3.0 -multidict==6.0.5 -mypy-extensions==1.0.0 neo4j-rust-ext -networkx==3.2.1 -nltk==3.8.1 -numpy==1.26.4 -omegaconf==2.3.0 -onnx==1.16.1 -onnxruntime==1.18.1 -openai==1.47.1 -opencv-python==4.8.0.76 -orjson==3.9.15 -packaging==23.2 -pandas==2.2.0 -pdf2image==1.17.0 -pdfminer.six==20221105 -pdfplumber==0.10.4 -pikepdf==8.11.0 -pillow==10.2.0 -pillow_heif==0.15.0 -portalocker==2.8.2 -proto-plus==1.23.0 -protobuf==4.23.4 -psutil==6.0.0 -pyasn1==0.6.0 -pyasn1_modules==0.4.0 -pycocotools==2.0.7 -pycparser==2.21 -pydantic==2.8.2 -pydantic_core==2.20.1 -pyparsing==3.0.9 -pypdf==4.0.1 -PyPDF2==3.0.1 -pypdfium2==4.27.0 -pytesseract==0.3.10 -python-dateutil==2.8.2 +nltk==3.9.1 +openai==1.55.1 +opencv-python==4.10.0.84 +psutil==6.1.0 +pydantic==2.9.0 python-dotenv==1.0.1 -python-iso639==2024.2.7 -python-magic==0.4.27 -python-multipart==0.0.9 -pytube==15.0.0 -pytz==2024.1 -PyYAML==6.0.1 -rapidfuzz==3.6.1 -regex==2023.12.25 -requests==2.32.3 -rsa==4.9 -s3transfer==0.10.1 -safetensors==0.4.1 -shapely==2.0.3 -six==1.16.0 -sniffio==1.3.1 -soupsieve==2.5 -starlette==0.37.2 -sse-starlette==2.1.2 +PyPDF2==3.0.1 +PyMuPDF==1.24.14 +starlette==0.41.3 +sse-starlette==2.1.3 starlette-session==0.4.3 -sympy==1.12 -tabulate==0.9.0 -tenacity==8.2.3 -tiktoken==0.7.0 -timm==0.9.12 -tokenizers==0.19 -tqdm==4.66.2 -transformers==4.42.3 -types-protobuf -types-requests -typing-inspect==0.9.0 -typing_extensions==4.12.2 -tzdata==2024.1 -unstructured==0.14.9 -unstructured-client==0.23.8 -unstructured-inference==0.7.36 -unstructured.pytesseract==0.3.12 -unstructured[all-docs]==0.14.9 +tqdm==4.67.1 +unstructured[all-docs]==0.16.6 urllib3==2.2.2 -uvicorn==0.30.1 -gunicorn==22.0.0 +uvicorn==0.32.1 +gunicorn==23.0.0 wikipedia==1.4.0 wrapt==1.16.0 yarl==1.9.4 -youtube-transcript-api==0.6.2 +youtube-transcript-api==0.6.3 zipp==3.17.0 -sentence-transformers==3.0.1 -google-cloud-logging==3.10.0 -PyMuPDF==1.24.5 +sentence-transformers==3.3.1 +google-cloud-logging==3.11.3 pypandoc==1.13 -graphdatascience==1.10 +graphdatascience==1.12 Secweb==1.11.0 -ragas==0.2.2 +ragas==0.2.6 rouge_score==0.1.2 +langchain-neo4j==0.1.1 \ No newline at end of file diff --git a/backend/score.py b/backend/score.py index 0c2884c25..62fb20b7b 100644 --- a/backend/score.py +++ b/backend/score.py @@ -36,6 +36,7 @@ from src.ragas_eval import * from starlette.types import ASGIApp, Message, Receive, Scope, Send import gzip +from langchain_neo4j import Neo4jGraph logger = CustomLogger() CHUNK_DIR = os.path.join(os.path.dirname(__file__), "chunks") @@ -581,7 +582,6 @@ async def generate(): graph = create_graph_database_connection(uri, userName, decoded_password, database) graphDb_data_Access = graphDBdataAccess(graph) result = graphDb_data_Access.get_current_status_document_node(file_name) - # print(f'Result of document status in SSE : {result}') if len(result) > 0: status = json.dumps({'fileName':file_name, 'status':result[0]['Status'], @@ -668,7 +668,7 @@ async def get_document_status(file_name, url, userName, password, database): } else: status = {'fileName':file_name, 'status':'Failed'} - print(f'Result of document status in refresh : {result}') + logging.info(f'Result of document status in refresh : {result}') return create_api_response('Success',message="",file_name=status) except Exception as e: message=f"Unable to get the document status" @@ -961,7 +961,7 @@ async def fetch_chunktext( async def backend_connection_configuation(): try: graph = Neo4jGraph() - print(f'login connection status of object: {graph}') + logging.info(f'login connection status of object: {graph}') if graph is not None: graph_connection = True isURI = os.getenv('NEO4J_URI') diff --git a/backend/src/QA_integration.py b/backend/src/QA_integration.py index fff7d7923..f50a36efb 100644 --- a/backend/src/QA_integration.py +++ b/backend/src/QA_integration.py @@ -4,15 +4,13 @@ import logging import threading -from concurrent.futures import ThreadPoolExecutor from datetime import datetime from typing import Any from dotenv import load_dotenv - -# LangChain imports -from langchain_community.vectorstores.neo4j_vector import Neo4jVector -from langchain_community.chat_message_histories import Neo4jChatMessageHistory +from langchain_neo4j import Neo4jVector +from langchain_neo4j import Neo4jChatMessageHistory +from langchain_neo4j import GraphCypherQAChain from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain_core.output_parsers import StrOutputParser from langchain_core.runnables import RunnableBranch @@ -21,7 +19,6 @@ from langchain.retrievers.document_compressors import EmbeddingsFilter, DocumentCompressorPipeline from langchain_text_splitters import TokenTextSplitter from langchain_core.messages import HumanMessage, AIMessage -from langchain.chains import GraphCypherQAChain from langchain_community.chat_message_histories import ChatMessageHistory from langchain_core.callbacks import StdOutCallbackHandler, BaseCallbackHandler @@ -38,8 +35,6 @@ from src.llm import get_llm from src.shared.common_fn import load_embedding_model from src.shared.constants import * -from src.graphDB_dataAccess import graphDBdataAccess -from src.ragas_eval import get_ragas_metrics load_dotenv() EMBEDDING_MODEL = os.getenv('EMBEDDING_MODEL') diff --git a/backend/src/create_chunks.py b/backend/src/create_chunks.py index 621785a31..d5e93d14f 100644 --- a/backend/src/create_chunks.py +++ b/backend/src/create_chunks.py @@ -1,8 +1,7 @@ from langchain_text_splitters import TokenTextSplitter from langchain.docstore.document import Document -from langchain_community.graphs import Neo4jGraph +from langchain_neo4j import Neo4jGraph import logging -import os from src.document_sources.youtube import get_chunks_with_timestamps, get_calculated_timestamps import re @@ -25,7 +24,6 @@ def split_file_into_chunks(self): A list of chunks each of which is a langchain Document. """ logging.info("Split file into smaller chunks") - # number_of_chunks_allowed = int(os.environ.get('NUMBER_OF_CHUNKS_ALLOWED')) text_splitter = TokenTextSplitter(chunk_size=200, chunk_overlap=20) if 'page' in self.pages[0].metadata: chunks = [] diff --git a/backend/src/diffbot_transformer.py b/backend/src/diffbot_transformer.py index a8e8db3fb..e16e54efb 100644 --- a/backend/src/diffbot_transformer.py +++ b/backend/src/diffbot_transformer.py @@ -1,5 +1,6 @@ from langchain_experimental.graph_transformers.diffbot import DiffbotGraphTransformer -from langchain_community.graphs import Neo4jGraph +#from langchain_community.graphs import Neo4jGraph +from langchain_neo4j import Neo4jGraph from langchain.docstore.document import Document from typing import List import os diff --git a/backend/src/document_sources/gcs_bucket.py b/backend/src/document_sources/gcs_bucket.py index 91830f591..851692462 100644 --- a/backend/src/document_sources/gcs_bucket.py +++ b/backend/src/document_sources/gcs_bucket.py @@ -101,15 +101,12 @@ def merge_file_gcs(bucket_name, original_file_name: str, folder_name_sha1_hashed try: storage_client = storage.Client() bucket = storage_client.bucket(bucket_name) - # Retrieve chunks from GCS - # blobs = storage_client.list_blobs(bucket_name, prefix=folder_name_sha1_hashed) - # print(f'before sorted blobs: {blobs}') chunks = [] for i in range(1,total_chunks+1): blob_name = folder_name_sha1_hashed + '/' + f"{original_file_name}_part_{i}" blob = bucket.blob(blob_name) if blob.exists(): - print(f'Blob Name: {blob.name}') + logging.info(f'Blob Name: {blob.name}') chunks.append(blob.download_as_bytes()) blob.delete() diff --git a/backend/src/document_sources/local_file.py b/backend/src/document_sources/local_file.py index ed46210f4..3d5bc08db 100644 --- a/backend/src/document_sources/local_file.py +++ b/backend/src/document_sources/local_file.py @@ -20,10 +20,8 @@ def load_document_content(file_path): if Path(file_path).suffix.lower() == '.pdf': - print("in if") return PyMuPDFLoader(file_path) else: - print("in else") return UnstructuredFileLoader(file_path, mode="elements",autodetect_encoding=True) def get_documents_from_file_by_path(file_path,file_name): diff --git a/backend/src/document_sources/youtube.py b/backend/src/document_sources/youtube.py index dacda09f0..dee97e230 100644 --- a/backend/src/document_sources/youtube.py +++ b/backend/src/document_sources/youtube.py @@ -1,25 +1,16 @@ -from pathlib import Path from langchain.docstore.document import Document -from langchain_community.document_loaders import YoutubeLoader -from pytube import YouTube from youtube_transcript_api import YouTubeTranscriptApi import logging from urllib.parse import urlparse,parse_qs from difflib import SequenceMatcher from datetime import timedelta -from langchain_community.document_loaders.youtube import TranscriptFormat from src.shared.constants import YOUTUBE_CHUNK_SIZE_SECONDS from typing import List, Dict, Any import os import re -from langchain_community.document_loaders import GoogleApiClient, GoogleApiYoutubeLoader def get_youtube_transcript(youtube_id): try: - #transcript = YouTubeTranscriptApi.get_transcript(youtube_id) - # transcript_list = YouTubeTranscriptApi.list_transcripts(youtube_id) - # transcript = transcript_list.find_transcript(["en"]) - # transcript_pieces: List[Dict[str, Any]] = transcript.fetch() proxy = os.environ.get("YOUTUBE_TRANSCRIPT_PROXY") proxies = { 'https': proxy } transcript_pieces = YouTubeTranscriptApi.get_transcript(youtube_id, proxies = proxies) @@ -28,15 +19,6 @@ def get_youtube_transcript(youtube_id): message = f"Youtube transcript is not available for youtube Id: {youtube_id}" raise Exception(message) -# def get_youtube_combined_transcript(youtube_id): -# try: -# transcript_dict = get_youtube_transcript(youtube_id) -# transcript = YouTubeTranscriptApi.get_transcript(youtube_id) -# return transcript -# except Exception as e: -# message = f"Youtube transcript is not available for youtube Id: {youtube_id}" -# raise Exception(message) - def get_youtube_combined_transcript(youtube_id): try: transcript_dict = get_youtube_transcript(youtube_id) @@ -64,25 +46,6 @@ def create_youtube_url(url): def get_documents_from_youtube(url): try: match = re.search(r'(?:v=)([0-9A-Za-z_-]{11})\s*',url) - # youtube_loader = YoutubeLoader.from_youtube_url(url, - # language=["en-US", "en-gb", "en-ca", "en-au","zh-CN", "zh-Hans", "zh-TW", "fr-FR","de-DE","it-IT","ja-JP","pt-BR","ru-RU","es-ES"], - # translation = "en", - # add_video_info=True, - # transcript_format=TranscriptFormat.CHUNKS, - # chunk_size_seconds=YOUTUBE_CHUNK_SIZE_SECONDS) - # video_id = parse_qs(urlparse(url).query).get('v') - # cred_path = os.path.join(os.getcwd(),"llm-experiments_credentials.json") - # print(f'Credential file path on youtube.py {cred_path}') - # google_api_client = GoogleApiClient(service_account_path=Path(cred_path)) - # youtube_loader_channel = GoogleApiYoutubeLoader( - # google_api_client=google_api_client, - # video_ids=[video_id[0].strip()], add_video_info=True - # ) - # youtube_transcript = youtube_loader_channel.load() - # pages = youtube_loader.load() - # print(f'youtube page_content: {youtube_transcript[0].page_content}') - # print(f'youtube id: {youtube_transcript[0].metadata["id"]}') - # print(f'youtube title: {youtube_transcript[0].metadata["snippet"]["title"]}') transcript= get_youtube_transcript(match.group(1)) transcript_content='' counter = YOUTUBE_CHUNK_SIZE_SECONDS diff --git a/backend/src/graphDB_dataAccess.py b/backend/src/graphDB_dataAccess.py index 41a37631c..aa9034f4c 100644 --- a/backend/src/graphDB_dataAccess.py +++ b/backend/src/graphDB_dataAccess.py @@ -1,7 +1,6 @@ import logging import os -from datetime import datetime -from langchain_community.graphs import Neo4jGraph +from langchain_neo4j import Neo4jGraph from src.shared.common_fn import create_gcs_bucket_folder_name_hashed, delete_uploaded_local_file, load_embedding_model from src.document_sources.gcs_bucket import delete_file_from_gcs from src.shared.constants import BUCKET_UPLOAD,NODEREL_COUNT_QUERY_WITH_COMMUNITY, NODEREL_COUNT_QUERY_WITHOUT_COMMUNITY @@ -103,7 +102,7 @@ def update_source_node(self, obj_source_node:sourceNode): param= {"props":params} - print(f'Base Param value 1 : {param}') + logging.info(f'Base Param value 1 : {param}') query = "MERGE(d:Document {fileName :$props.fileName}) SET d += $props" logging.info("Update source node properties") self.graph.query(query,param) @@ -411,7 +410,7 @@ def get_duplicate_nodes_list(self): def merge_duplicate_nodes(self,duplicate_nodes_list): nodes_list = json.loads(duplicate_nodes_list) - print(f'Nodes list to merge {nodes_list}') + logging.info(f'Nodes list to merge {nodes_list}') query = """ UNWIND $rows AS row CALL { with row diff --git a/backend/src/graph_query.py b/backend/src/graph_query.py index 86739ba6c..dc5a64a2c 100644 --- a/backend/src/graph_query.py +++ b/backend/src/graph_query.py @@ -207,8 +207,6 @@ def get_graph_results(uri, username, password,database,document_names): document_nodes = extract_node_elements(records) document_relationships = extract_relationships(records) - print(query) - logging.info(f"no of nodes : {len(document_nodes)}") logging.info(f"no of relations : {len(document_relationships)}") result = { diff --git a/backend/src/llm.py b/backend/src/llm.py index de50fa181..f19648ed6 100644 --- a/backend/src/llm.py +++ b/backend/src/llm.py @@ -6,17 +6,13 @@ from langchain_groq import ChatGroq from langchain_google_vertexai import HarmBlockThreshold, HarmCategory from langchain_experimental.graph_transformers.diffbot import DiffbotGraphTransformer -import concurrent.futures -from concurrent.futures import ThreadPoolExecutor from langchain_experimental.graph_transformers import LLMGraphTransformer -from langchain_core.prompts import ChatPromptTemplate from langchain_anthropic import ChatAnthropic from langchain_fireworks import ChatFireworks from langchain_aws import ChatBedrock from langchain_community.chat_models import ChatOllama import boto3 import google.auth -from src.shared.constants import MODEL_VERSIONS, PROMPT_TO_ALL_LLMs def get_llm(model: str): """Retrieve the specified language model based on the model name.""" @@ -27,7 +23,6 @@ def get_llm(model: str): if "gemini" in model: model_name = env_value credentials, project_id = google.auth.default() - #model_name = MODEL_VERSIONS[model] llm = ChatVertexAI( model_name=model_name, #convert_system_message_to_human=True, @@ -43,7 +38,6 @@ def get_llm(model: str): }, ) elif "openai" in model: - #model_name = MODEL_VERSIONS[model] model_name, api_key = env_value.split(",") llm = ChatOpenAI( api_key=api_key, @@ -175,20 +169,7 @@ async def get_graph_document_list( allowed_nodes=allowedNodes, allowed_relationships=allowedRelationship, ignore_tool_usage=True, - #prompt = ChatPromptTemplate.from_messages(["system",PROMPT_TO_ALL_LLMs]) ) - # with ThreadPoolExecutor(max_workers=10) as executor: - # for chunk in combined_chunk_document_list: - # chunk_doc = Document( - # page_content=chunk.page_content.encode("utf-8"), metadata=chunk.metadata - # ) - # futures.append( - # executor.submit(llm_transformer.convert_to_graph_documents, [chunk_doc]) - # ) - - # for i, future in enumerate(concurrent.futures.as_completed(futures)): - # graph_document = future.result() - # graph_document_list.append(graph_document[0]) if isinstance(llm,DiffbotGraphTransformer): graph_document_list = llm_transformer.convert_to_graph_documents(combined_chunk_document_list) diff --git a/backend/src/main.py b/backend/src/main.py index c5add5343..b2c56caaa 100644 --- a/backend/src/main.py +++ b/backend/src/main.py @@ -1,4 +1,4 @@ -from langchain_community.graphs import Neo4jGraph +from langchain_neo4j import Neo4jGraph from src.shared.constants import (BUCKET_UPLOAD, PROJECT_ID, QUERY_TO_GET_CHUNKS, QUERY_TO_DELETE_EXISTING_ENTITIES, QUERY_TO_GET_LAST_PROCESSED_CHUNK_POSITION, @@ -8,7 +8,6 @@ DELETE_ENTITIES_AND_START_FROM_BEGINNING, QUERY_TO_GET_NODES_AND_RELATIONS_OF_A_DOCUMENT) from src.shared.schema_extraction import schema_extraction_from_text -from langchain_community.document_loaders import GoogleApiClient, GoogleApiYoutubeLoader from dotenv import load_dotenv from datetime import datetime import logging @@ -27,7 +26,6 @@ import re from langchain_community.document_loaders import WikipediaLoader, WebBaseLoader import warnings -from pytube import YouTube import sys import shutil import urllib.parse @@ -142,34 +140,13 @@ def create_source_node_graph_url_youtube(graph, model, source_url, source_type): obj_source_node.created_at = datetime.now() match = re.search(r'(?:v=)([0-9A-Za-z_-]{11})\s*',obj_source_node.url) logging.info(f"match value: {match}") - # file_path = os.path.join(os.path.dirname(__file__),"llm-experiments_credentials.json") - # logging.info(f'file path {file_path}') - - # if os.path.exists(file_path): - # logging.info("File path exist") - # with open(file_path,'r') as file: - # data = json.load(file) - # # logging.info(f"Project id : {data['project_id']}") - # # logging.info(f"Universal domain: {data['universe_domain']}") - # else: - # logging.warning("credntial file path not exist") - video_id = parse_qs(urlparse(youtube_url).query).get('v') - - # google_api_client = GoogleApiClient(service_account_path=Path(file_path)) - # youtube_loader_channel = GoogleApiYoutubeLoader( - # google_api_client=google_api_client, - # video_ids=[video_id[0].strip()], add_video_info=True - # ) - # youtube_transcript = youtube_loader_channel.load() - # page_content = youtube_transcript[0].page_content - - obj_source_node.file_name = match.group(1)#youtube_transcript[0].metadata["snippet"]["title"] - #obj_source_node.file_name = YouTube(youtube_url).title + obj_source_node.file_name = match.group(1) transcript= get_youtube_combined_transcript(match.group(1)) - print(transcript) + logging.info(f"Youtube transcript : {transcript}") if transcript==None or len(transcript)==0: message = f"Youtube transcript is not available for : {obj_source_node.file_name}" + logging.info(f"Youtube transcript is not available for : {obj_source_node.file_name}") raise Exception(message) else: obj_source_node.file_size = sys.getsizeof(transcript) @@ -212,7 +189,7 @@ def create_source_node_graph_url_wikipedia(graph, model, wiki_query, source_type async def extract_graph_from_file_local_file(uri, userName, password, database, model, merged_file_path, fileName, allowedNodes, allowedRelationship, retry_condition): logging.info(f'Process file name :{fileName}') - if retry_condition is None: + if not retry_condition: gcs_file_cache = os.environ.get('GCS_FILE_CACHE') if gcs_file_cache == 'True': folder_name = create_gcs_bucket_folder_name_hashed(uri, fileName) @@ -226,7 +203,7 @@ async def extract_graph_from_file_local_file(uri, userName, password, database, return await processing_source(uri, userName, password, database, model, fileName, [], allowedNodes, allowedRelationship, True, merged_file_path, retry_condition) async def extract_graph_from_file_s3(uri, userName, password, database, model, source_url, aws_access_key_id, aws_secret_access_key, file_name, allowedNodes, allowedRelationship, retry_condition): - if retry_condition is None: + if not retry_condition: if(aws_access_key_id==None or aws_secret_access_key==None): raise Exception('Please provide AWS access and secret keys') else: @@ -240,9 +217,8 @@ async def extract_graph_from_file_s3(uri, userName, password, database, model, s return await processing_source(uri, userName, password, database, model, file_name, [], allowedNodes, allowedRelationship, retry_condition=retry_condition) async def extract_graph_from_web_page(uri, userName, password, database, model, source_url, file_name, allowedNodes, allowedRelationship, retry_condition): - if retry_condition is None: + if not retry_condition: file_name, pages = get_documents_from_web_page(source_url) - if pages==None or len(pages)==0: raise Exception(f'Content is not available for given URL : {file_name}') return await processing_source(uri, userName, password, database, model, file_name, pages, allowedNodes, allowedRelationship) @@ -250,7 +226,7 @@ async def extract_graph_from_web_page(uri, userName, password, database, model, return await processing_source(uri, userName, password, database, model, file_name, [], allowedNodes, allowedRelationship, retry_condition=retry_condition) async def extract_graph_from_file_youtube(uri, userName, password, database, model, source_url, file_name, allowedNodes, allowedRelationship, retry_condition): - if retry_condition is None: + if not retry_condition: file_name, pages = get_documents_from_youtube(source_url) if pages==None or len(pages)==0: @@ -260,7 +236,7 @@ async def extract_graph_from_file_youtube(uri, userName, password, database, mod return await processing_source(uri, userName, password, database, model, file_name, [], allowedNodes, allowedRelationship, retry_condition=retry_condition) async def extract_graph_from_file_Wikipedia(uri, userName, password, database, model, wiki_query, language, file_name, allowedNodes, allowedRelationship, retry_condition): - if retry_condition is None: + if not retry_condition: file_name, pages = get_documents_from_Wikipedia(wiki_query, language) if pages==None or len(pages)==0: raise Exception(f'Wikipedia page is not available for file : {file_name}') @@ -269,7 +245,7 @@ async def extract_graph_from_file_Wikipedia(uri, userName, password, database, m return await processing_source(uri, userName, password, database, model, file_name,[], allowedNodes, allowedRelationship, retry_condition=retry_condition) async def extract_graph_from_file_gcs(uri, userName, password, database, model, gcs_project_id, gcs_bucket_name, gcs_bucket_folder, gcs_blob_filename, access_token, file_name, allowedNodes, allowedRelationship, retry_condition): - if retry_condition is None: + if not retry_condition: file_name, pages = get_documents_from_gcs(gcs_project_id, gcs_bucket_name, gcs_bucket_folder, gcs_blob_filename, access_token) if pages==None or len(pages)==0: raise Exception(f'File content is not available for file : {file_name}') @@ -303,7 +279,6 @@ async def processing_source(uri, userName, password, database, model, file_name, logging.info(f'Time taken database connection: {elapsed_create_connection:.2f} seconds') uri_latency["create_connection"] = f'{elapsed_create_connection:.2f}' graphDb_data_Access = graphDBdataAccess(graph) - start_get_chunkId_chunkDoc_list = time.time() total_chunks, chunkId_chunkDoc_list = get_chunkId_chunkDoc_list(graph, file_name, pages, retry_condition) end_get_chunkId_chunkDoc_list = time.time() @@ -499,12 +474,10 @@ async def processing_chunks(chunkId_chunkDoc_list,graph,uri, userName, password, node_count += len(distinct_nodes) rel_count += len(relations) - print(f'node count internal func:{node_count}') - print(f'relation count internal func:{rel_count}') return node_count,rel_count,latency_processing_chunk def get_chunkId_chunkDoc_list(graph, file_name, pages, retry_condition): - if retry_condition is None: + if not retry_condition: logging.info("Break down file into chunks") bad_chars = ['"', "\n", "'"] for i in range(0,len(pages)): diff --git a/backend/src/make_relationships.py b/backend/src/make_relationships.py index 1ea2729e5..7d079fcf3 100644 --- a/backend/src/make_relationships.py +++ b/backend/src/make_relationships.py @@ -1,4 +1,4 @@ -from langchain_community.graphs import Neo4jGraph +from langchain_neo4j import Neo4jGraph from langchain.docstore.document import Document from src.shared.common_fn import load_embedding_model import logging diff --git a/backend/src/post_processing.py b/backend/src/post_processing.py index 7746df3d0..02fc7fb06 100644 --- a/backend/src/post_processing.py +++ b/backend/src/post_processing.py @@ -1,7 +1,7 @@ from neo4j import GraphDatabase import logging import time -from langchain_community.graphs import Neo4jGraph +from langchain_neo4j import Neo4jGraph import os from src.shared.common_fn import load_embedding_model diff --git a/backend/src/ragas_eval.py b/backend/src/ragas_eval.py index 687db37aa..c9f447242 100644 --- a/backend/src/ragas_eval.py +++ b/backend/src/ragas_eval.py @@ -8,11 +8,8 @@ from ragas.metrics import answer_relevancy, faithfulness from src.shared.common_fn import load_embedding_model from ragas.dataset_schema import SingleTurnSample -from ragas.metrics import BleuScore, RougeScore, SemanticSimilarity, ContextEntityRecall -from ragas.metrics._factual_correctness import FactualCorrectness +from ragas.metrics import RougeScore, SemanticSimilarity, ContextEntityRecall from ragas.llms import LangchainLLMWrapper -from langchain_openai import ChatOpenAI -from langchain.embeddings import OpenAIEmbeddings from ragas.embeddings import LangchainEmbeddingsWrapper import nltk diff --git a/backend/src/shared/common_fn.py b/backend/src/shared/common_fn.py index 916e01e89..0c0b4bea1 100644 --- a/backend/src/shared/common_fn.py +++ b/backend/src/shared/common_fn.py @@ -1,25 +1,15 @@ import hashlib import logging from src.document_sources.youtube import create_youtube_url -from langchain_community.embeddings.sentence_transformer import SentenceTransformerEmbeddings +from langchain_huggingface import HuggingFaceEmbeddings from langchain_google_vertexai import VertexAIEmbeddings from langchain_openai import OpenAIEmbeddings -from langchain.docstore.document import Document -from langchain_community.graphs import Neo4jGraph +from langchain_neo4j import Neo4jGraph from langchain_community.graphs.graph_document import GraphDocument from typing import List import re import os from pathlib import Path -from langchain_openai import ChatOpenAI -from langchain_google_vertexai import ChatVertexAI -from langchain_groq import ChatGroq -from langchain_google_vertexai import HarmBlockThreshold, HarmCategory -from langchain_experimental.graph_transformers.diffbot import DiffbotGraphTransformer -# from neo4j.debug import watch - -# watch("neo4j") - def check_url_source(source_type, yt_url:str=None, wiki_query:str=None): language='' @@ -86,11 +76,11 @@ def load_embedding_model(embedding_model_name: str): dimension = 768 logging.info(f"Embedding: Using Vertex AI Embeddings , Dimension:{dimension}") else: - embeddings = SentenceTransformerEmbeddings( + embeddings = HuggingFaceEmbeddings( model_name="all-MiniLM-L6-v2"#, cache_folder="/embedding_model" ) dimension = 384 - logging.info(f"Embedding: Using SentenceTransformer , Dimension:{dimension}") + logging.info(f"Embedding: Using Langchain HuggingFaceEmbeddings , Dimension:{dimension}") return embeddings, dimension def save_graphDocuments_in_neo4j(graph:Neo4jGraph, graph_document_list:List[GraphDocument]): From b09131e281f06139b768e2bac5c2fa488e8d757d Mon Sep 17 00:00:00 2001 From: aashipandya <156318202+aashipandya@users.noreply.github.com> Date: Tue, 3 Dec 2024 20:10:27 +0530 Subject: [PATCH 279/292] gcs file existance check and reprocess from last processed position check updates (#917) Co-authored-by: kaustubh-darekar --- README.md | 12 +++++++++++- backend/src/document_sources/gcs_bucket.py | 17 ++++++++++++----- backend/src/main.py | 11 ++++++----- backend/src/shared/constants.py | 12 +----------- backend/src/shared/schema_extraction.py | 1 - 5 files changed, 30 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 164e51f00..e37d3ddfe 100644 --- a/README.md +++ b/README.md @@ -161,7 +161,17 @@ Allow unauthenticated request : Yes | LLM_MODEL_CONFIG_ollama_ | Optional | | Set ollama config as - model_name,model_local_url for local deployments | | RAGAS_EMBEDDING_MODEL | Optional | openai | embedding model used by ragas evaluation framework | - +## LLMs Supported +1. OpenAI +2. Gemini +3. Azure OpenAI(dev) +4. Anthropic(dev) +5. Fireworks(dev) +6. Groq(dev) +7. Amazon Bedrock(dev) +8. Ollama(dev) +9. Diffbot +10. Other OpenAI compabtile baseurl models(dev) ## For local llms (Ollama) 1. Pull the docker imgage of ollama diff --git a/backend/src/document_sources/gcs_bucket.py b/backend/src/document_sources/gcs_bucket.py index 851692462..3aaf42e12 100644 --- a/backend/src/document_sources/gcs_bucket.py +++ b/backend/src/document_sources/gcs_bucket.py @@ -59,8 +59,14 @@ def get_documents_from_gcs(gcs_project_id, gcs_bucket_name, gcs_bucket_folder, g if access_token is None: storage_client = storage.Client(project=gcs_project_id) - loader = GCSFileLoader(project_name=gcs_project_id, bucket=gcs_bucket_name, blob=blob_name, loader_func=load_document_content) - pages = loader.load() + bucket = storage_client.bucket(gcs_bucket_name) + blob = bucket.blob(blob_name) + + if blob.exists(): + loader = GCSFileLoader(project_name=gcs_project_id, bucket=gcs_bucket_name, blob=blob_name, loader_func=load_document_content) + pages = loader.load() + else : + raise Exception('File does not exist, Please re-upload the file and try again.') else: creds= Credentials(access_token) storage_client = storage.Client(project=gcs_project_id, credentials=creds) @@ -77,7 +83,7 @@ def get_documents_from_gcs(gcs_project_id, gcs_bucket_name, gcs_bucket_folder, g text += page.extract_text() pages = [Document(page_content = text)] else: - raise Exception('Blob Not Found') + raise Exception(f'File Not Found in GCS bucket - {gcs_bucket_name}') return gcs_blob_filename, pages def upload_file_to_gcs(file_chunk, chunk_number, original_file_name, bucket_name, folder_name_sha1_hashed): @@ -143,7 +149,8 @@ def copy_failed_file(source_bucket_name,dest_bucket_name,folder_name, file_name) dest_bucket = storage_client.bucket(dest_bucket_name) folder_file_name = folder_name +'/'+file_name source_blob = source_bucket.blob(folder_file_name) - source_bucket.copy_blob(source_blob, dest_bucket, file_name) - logging.info(f'Failed file {file_name} copied to {dest_bucket_name} from {source_bucket_name} in GCS successfully') + if source_blob.exists(): + source_bucket.copy_blob(source_blob, dest_bucket, file_name) + logging.info(f'Failed file {file_name} copied to {dest_bucket_name} from {source_bucket_name} in GCS successfully') except Exception as e: raise Exception(e) diff --git a/backend/src/main.py b/backend/src/main.py index b2c56caaa..5ef1e4354 100644 --- a/backend/src/main.py +++ b/backend/src/main.py @@ -497,8 +497,8 @@ def get_chunkId_chunkDoc_list(graph, file_name, pages, retry_condition): chunkId_chunkDoc_list=[] chunks = graph.query(QUERY_TO_GET_CHUNKS, params={"filename":file_name}) - if chunks[0]['text'] is None or chunks[0]['text']=="" : - raise Exception(f"Chunks are not created for {file_name}. Please re-upload file and try.") + if chunks[0]['text'] is None or chunks[0]['text']=="" or not chunks : + raise Exception(f"Chunks are not created for {file_name}. Please re-upload file and try again.") else: for chunk in chunks: chunk_doc = Document(page_content=chunk['text'], metadata={'id':chunk['id'], 'position':chunk['position']}) @@ -507,15 +507,16 @@ def get_chunkId_chunkDoc_list(graph, file_name, pages, retry_condition): if retry_condition == START_FROM_LAST_PROCESSED_POSITION: logging.info(f"Retry : start_from_last_processed_position") starting_chunk = graph.query(QUERY_TO_GET_LAST_PROCESSED_CHUNK_POSITION, params={"filename":file_name}) - if starting_chunk[0]["position"] < len(chunkId_chunkDoc_list): + + if starting_chunk and starting_chunk[0]["position"] < len(chunkId_chunkDoc_list): return len(chunks), chunkId_chunkDoc_list[starting_chunk[0]["position"] - 1:] - elif starting_chunk[0]["position"] == len(chunkId_chunkDoc_list): + elif starting_chunk and starting_chunk[0]["position"] == len(chunkId_chunkDoc_list): starting_chunk = graph.query(QUERY_TO_GET_LAST_PROCESSED_CHUNK_WITHOUT_ENTITY, params={"filename":file_name}) return len(chunks), chunkId_chunkDoc_list[starting_chunk[0]["position"] - 1:] else: - raise Exception(f"All chunks of {file_name} are alreday processed. If you want to re-process, Please start from begnning") + raise Exception(f"All chunks of file are alreday processed. If you want to re-process, Please start from begnning") else: logging.info(f"Retry : start_from_beginning with chunks {len(chunkId_chunkDoc_list)}") diff --git a/backend/src/shared/constants.py b/backend/src/shared/constants.py index bf96532d9..8307dc3c9 100644 --- a/backend/src/shared/constants.py +++ b/backend/src/shared/constants.py @@ -1,14 +1,4 @@ -MODEL_VERSIONS = { - "openai-gpt-3.5": "gpt-3.5-turbo-0125", - "gemini-1.0-pro": "gemini-1.0-pro-001", - "gemini-1.5-pro": "gemini-1.5-pro-002", - "gemini-1.5-flash": "gemini-1.5-flash-002", - "openai-gpt-4": "gpt-4-turbo-2024-04-09", - "diffbot" : "gpt-4-turbo-2024-04-09", - "openai-gpt-4o-mini": "gpt-4o-mini-2024-07-18", - "openai-gpt-4o":"gpt-4o-2024-08-06", - "groq-llama3" : "llama3-70b-8192" - } + OPENAI_MODELS = ["openai-gpt-3.5", "openai-gpt-4o", "openai-gpt-4o-mini"] GEMINI_MODELS = ["gemini-1.0-pro", "gemini-1.5-pro", "gemini-1.5-flash"] GROQ_MODELS = ["groq-llama3"] diff --git a/backend/src/shared/schema_extraction.py b/backend/src/shared/schema_extraction.py index 80954ba65..1b7f76c92 100644 --- a/backend/src/shared/schema_extraction.py +++ b/backend/src/shared/schema_extraction.py @@ -2,7 +2,6 @@ #from langchain_core.pydantic_v1 import BaseModel, Field from pydantic.v1 import BaseModel, Field from src.llm import get_llm -from src.shared.constants import MODEL_VERSIONS from langchain_core.prompts import ChatPromptTemplate class Schema(BaseModel): From 6e9edce7e3ecafea11ef4455c0fe65cc97663051 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Wed, 4 Dec 2024 05:13:24 +0000 Subject: [PATCH 280/292] format and lint fixes --- frontend/src/components/BreakDownPopOver.tsx | 2 +- frontend/src/components/ChatBot/Chatbot.tsx | 12 ++++++------ frontend/src/components/Content.tsx | 4 ++-- .../src/components/Graph/GraphViewModal.tsx | 16 ++++++++-------- frontend/src/components/Layout/PageLayout.tsx | 17 +++++------------ .../Deduplication/index.tsx | 4 ++-- .../PostProcessingCheckList/SelectedJobList.tsx | 4 ++-- frontend/src/utils/Utils.ts | 2 +- 8 files changed, 27 insertions(+), 34 deletions(-) diff --git a/frontend/src/components/BreakDownPopOver.tsx b/frontend/src/components/BreakDownPopOver.tsx index 01ebc4f20..f6798bf97 100644 --- a/frontend/src/components/BreakDownPopOver.tsx +++ b/frontend/src/components/BreakDownPopOver.tsx @@ -11,7 +11,7 @@ export default function BreakDownPopOver({ file, isNodeCount = true }: { file: C - + } > diff --git a/frontend/src/components/ChatBot/Chatbot.tsx b/frontend/src/components/ChatBot/Chatbot.tsx index 877dcdab4..aa84764bc 100644 --- a/frontend/src/components/ChatBot/Chatbot.tsx +++ b/frontend/src/components/ChatBot/Chatbot.tsx @@ -249,7 +249,7 @@ const Chatbot: FC = (props) => { } else { setListMessages((prev) => prev.map((msg) => - msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg + (msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg) ) ); } @@ -264,7 +264,7 @@ const Chatbot: FC = (props) => { } else { setListMessages((prev) => prev.map((msg) => - msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg + (msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg) ) ); } @@ -273,7 +273,7 @@ const Chatbot: FC = (props) => { console.error(`API call failed for mode ${mode}:`, result.reason); setListMessages((prev) => prev.map((msg) => - msg.id === chatbotMessageId + (msg.id === chatbotMessageId ? { ...msg, modes: { @@ -281,7 +281,7 @@ const Chatbot: FC = (props) => { [mode]: { message: 'Failed to fetch response for this mode.', error: result.reason }, }, } - : msg + : msg) ) ); } @@ -294,7 +294,7 @@ const Chatbot: FC = (props) => { if (error instanceof Error) { setListMessages((prev) => prev.map((msg) => - msg.id === chatbotMessageId + (msg.id === chatbotMessageId ? { ...msg, isLoading: false, @@ -306,7 +306,7 @@ const Chatbot: FC = (props) => { }, }, } - : msg + : msg) ) ); } diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index 932557dd3..449a47387 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -89,7 +89,7 @@ const Content: React.FC = ({ processedCount, setProcessedCount, setchatModes, - model + model, } = useFileContext(); const [viewPoint, setViewPoint] = useState<'tableView' | 'showGraphView' | 'chatInfoView' | 'neighborView'>( 'tableView' @@ -537,7 +537,7 @@ const Content: React.FC = ({ setProcessedCount(0); setConnectionStatus(false); localStorage.removeItem('password'); - localStorage.removeItem('selectedModel') + localStorage.removeItem('selectedModel'); setUserCredentials({ uri: '', password: '', userName: '', database: '' }); setSelectedNodes([]); setSelectedRels([]); diff --git a/frontend/src/components/Graph/GraphViewModal.tsx b/frontend/src/components/Graph/GraphViewModal.tsx index b93cf4b98..97a55144b 100644 --- a/frontend/src/components/Graph/GraphViewModal.tsx +++ b/frontend/src/components/Graph/GraphViewModal.tsx @@ -64,10 +64,10 @@ const GraphViewModal: React.FunctionComponent = ({ graphType.includes('DocumentChunk') && graphType.includes('Entities') ? queryMap.DocChunkEntities : graphType.includes('DocumentChunk') - ? queryMap.DocChunks - : graphType.includes('Entities') - ? queryMap.Entities - : ''; + ? queryMap.DocChunks + : graphType.includes('Entities') + ? queryMap.Entities + : ''; // fit graph to original position const handleZoomToFit = () => { @@ -114,10 +114,10 @@ const GraphViewModal: React.FunctionComponent = ({ const nodeRelationshipData = viewPoint === graphLabels.showGraphView ? await graphQueryAPI( - userCredentials as UserCredentials, - graphQuery, - selectedRows?.map((f) => f.name) - ) + userCredentials as UserCredentials, + graphQuery, + selectedRows?.map((f) => f.name) + ) : await graphQueryAPI(userCredentials as UserCredentials, graphQuery, [inspectedName ?? '']); return nodeRelationshipData; } catch (error: any) { diff --git a/frontend/src/components/Layout/PageLayout.tsx b/frontend/src/components/Layout/PageLayout.tsx index 71908bc64..88f5c7386 100644 --- a/frontend/src/components/Layout/PageLayout.tsx +++ b/frontend/src/components/Layout/PageLayout.tsx @@ -18,7 +18,6 @@ import { useNavigate } from 'react-router'; const ConnectionModal = lazy(() => import('../Popups/ConnectionModal/ConnectionModal')); - const PageLayout: React.FC = () => { const [openConnection, setOpenConnection] = useState({ openPopUp: false, @@ -161,8 +160,7 @@ const PageLayout: React.FC = () => { setConnectionStatus(Boolean(connectionData.data.graph_connection)); setIsBackendConnected(true); handleDisconnectButtonState(false); - } - else if (!session) { + } else if (!session) { setUserCredentials(envCredentials); localStorage.setItem( 'neo4j.connection', @@ -181,27 +179,22 @@ const PageLayout: React.FC = () => { setIsReadOnlyUser(envCredentials.isReadonlyUser); handleDisconnectButtonState(false); } - } - else { - if (session && !isDev) { + } else if (session && !isDev) { // For PROD, picking the session values setUserCredentialsFromSession(session as string); setConnectionStatus(true); handleDisconnectButtonState(true); - return; - } - else { + + } else { setOpenConnection((prev) => ({ ...prev, openPopUp: true })); handleDisconnectButtonState(true); } - } } catch (error) { console.error('Error in DEV session handling:', error); if (session) { setUserCredentialsFromSession(session as string); setConnectionStatus(true); - } - else { + } else { setErrorMessage(backendApiResponse?.data.error); setOpenConnection((prev) => ({ ...prev, openPopUp: true })); } diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx index df30c25c1..d59b46e21 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx @@ -104,12 +104,12 @@ export default function DeduplicationTab() { const onRemove = (nodeid: string, similarNodeId: string) => { setDuplicateNodes((prev) => { return prev.map((d) => - d.e.elementId === nodeid + (d.e.elementId === nodeid ? { ...d, similar: d.similar.filter((n) => n.elementId != similarNodeId), } - : d + : d) ); }); }; diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx index fc5f39206..447b1f846 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx @@ -11,11 +11,11 @@ export default function SelectedJobList({ }) { const ongoingPostProcessingTasks = useMemo( () => - isGdsActive + (isGdsActive ? postProcessingTasks.includes('enable_communities') ? postProcessingTasks : postProcessingTasks.filter((s) => s != 'enable_communities') - : postProcessingTasks.filter((s) => s != 'enable_communities'), + : postProcessingTasks.filter((s) => s != 'enable_communities')), [isGdsActive, postProcessingTasks] ); return ( diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index 82217535d..7314c55e7 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -395,7 +395,7 @@ export const isFileCompleted = (waitingFile: CustomFile, item: SourceNode) => waitingFile && item.status === 'Completed'; export const calculateProcessedCount = (prev: number, batchSize: number) => - prev === batchSize ? batchSize - 1 : prev + 1; + (prev === batchSize ? batchSize - 1 : prev + 1); export const isProcessingFileValid = (item: SourceNode, userCredentials: UserCredentials) => { return item.status === 'Processing' && item.fileName != undefined && userCredentials && userCredentials.database; From a9420ae151a9e9ed2af82fcae9821323913ee823 Mon Sep 17 00:00:00 2001 From: aashipandya <156318202+aashipandya@users.noreply.github.com> Date: Wed, 4 Dec 2024 18:08:53 +0530 Subject: [PATCH 281/292] updated requirements (#923) --- backend/requirements.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/backend/requirements.txt b/backend/requirements.txt index de1fc1136..1df0ff4de 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -2,7 +2,7 @@ asyncio==3.4.3 boto3==1.35.69 botocore==1.35.69 certifi==2024.8.30 -fastapi==0.115.5 +fastapi==0.115.6 fastapi-health==0.4.0 google-api-core==2.23.0 google-auth==2.36.0 @@ -32,6 +32,7 @@ opencv-python==4.10.0.84 psutil==6.1.0 pydantic==2.9.0 python-dotenv==1.0.1 +python-magic==0.4.27 PyPDF2==3.0.1 PyMuPDF==1.24.14 starlette==0.41.3 @@ -39,6 +40,9 @@ sse-starlette==2.1.3 starlette-session==0.4.3 tqdm==4.67.1 unstructured[all-docs]==0.16.6 +unstructured==0.16.6 +unstructured-client==0.26.2 +unstructured-inference==0.8.1 urllib3==2.2.2 uvicorn==0.32.1 gunicorn==23.0.0 From 8ce169306bddd287c663fabd1969b60e9e2bc8b5 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Thu, 5 Dec 2024 11:29:47 +0530 Subject: [PATCH 282/292] Update Constants.ts --- frontend/src/utils/Constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index 6044cb748..d83000eca 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -366,5 +366,5 @@ export const metricsinfo: Record = { answer_relevancy: "Determines How well the answer addresses the user's question.", rouge_score: 'Determines How much the generated answer matches the reference answer, word-for-word.', semantic_score: 'Determines How well the generated answer understands the meaning of the reference answer.', - context_entity_recall_score: 'Determines the recall of entities present in both reference and retrieved contexts', + context_entity_recall_score: 'Determines the recall of entities present in both generated answer and retrieved contexts', }; From cc3dc3d8e97affa00bfede1cb1683f22fd77ae59 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Thu, 5 Dec 2024 11:59:06 +0530 Subject: [PATCH 283/292] Metric table issues (#921) * fixed the table issues * hiding context recall check * eval error with gemini resolved * context reacall metric fix --------- Co-authored-by: kaustubh-darekar --- backend/src/ragas_eval.py | 48 +++++++++++++------ .../components/ChatBot/ChatModesSwitch.tsx | 4 +- .../components/ChatBot/CommonChatActions.tsx | 8 +++- .../src/components/ChatBot/MetricsTab.tsx | 18 +------ .../components/ChatBot/MultiModeMetrics.tsx | 22 ++------- 5 files changed, 45 insertions(+), 55 deletions(-) diff --git a/backend/src/ragas_eval.py b/backend/src/ragas_eval.py index c9f447242..29f7e026c 100644 --- a/backend/src/ragas_eval.py +++ b/backend/src/ragas_eval.py @@ -5,7 +5,7 @@ from datasets import Dataset from dotenv import load_dotenv from ragas import evaluate -from ragas.metrics import answer_relevancy, faithfulness +from ragas.metrics import answer_relevancy, faithfulness,context_entity_recall from src.shared.common_fn import load_embedding_model from ragas.dataset_schema import SingleTurnSample from ragas.metrics import RougeScore, SemanticSimilarity, ContextEntityRecall @@ -24,25 +24,29 @@ def get_ragas_metrics(question: str, context: list, answer: list, model: str): try: start_time = time.time() dataset = Dataset.from_dict( - {"question": [question] * len(answer), "answer": answer, "contexts": [[ctx] for ctx in context]} + {"question": [question] * len(answer),"reference": answer, "answer": answer, "contexts": [[ctx] for ctx in context]} ) logging.info("Evaluation dataset created successfully.") if ("diffbot" in model) or ("ollama" in model): raise ValueError(f"Unsupported model for evaluation: {model}") + elif ("gemini" in model): + llm, model_name = get_llm(model=model) + llm = LangchainLLMWrapper(llm,is_finished_parser=custom_is_finished_parser) else: llm, model_name = get_llm(model=model) + llm = LangchainLLMWrapper(llm) logging.info(f"Evaluating with model: {model_name}") score = evaluate( dataset=dataset, - metrics=[faithfulness, answer_relevancy], + metrics=[faithfulness, answer_relevancy,context_entity_recall], llm=llm, embeddings=EMBEDDING_FUNCTION, ) score_dict = ( - score.to_pandas()[["faithfulness", "answer_relevancy"]] + score.to_pandas()[["faithfulness", "answer_relevancy","context_entity_recall"]] .fillna(0) .round(4) .to_dict(orient="list") @@ -67,13 +71,10 @@ async def get_additional_metrics(question: str, contexts: list, answers: list, r if ("diffbot" in model_name) or ("ollama" in model_name): raise ValueError(f"Unsupported model for evaluation: {model_name}") llm, model_name = get_llm(model=model_name) - ragas_llm = LangchainLLMWrapper(llm) embeddings = EMBEDDING_FUNCTION embedding_model = LangchainEmbeddingsWrapper(embeddings=embeddings) rouge_scorer = RougeScore() semantic_scorer = SemanticSimilarity() - entity_recall_scorer = ContextEntityRecall() - entity_recall_scorer.llm = ragas_llm semantic_scorer.embeddings = embedding_model metrics = [] for response, context in zip(answers, contexts): @@ -82,18 +83,35 @@ async def get_additional_metrics(question: str, contexts: list, answers: list, r rouge_score = round(rouge_score,4) semantic_score = await semantic_scorer.single_turn_ascore(sample) semantic_score = round(semantic_score, 4) - if "gemini" in model_name: - entity_recall_score = "Not Available" - else: - entity_sample = SingleTurnSample(reference=reference, retrieved_contexts=[context]) - entity_recall_score = await entity_recall_scorer.single_turn_ascore(entity_sample) - entity_recall_score = round(entity_recall_score, 4) metrics.append({ "rouge_score": rouge_score, "semantic_score": semantic_score, - "context_entity_recall_score": entity_recall_score }) return metrics except Exception as e: logging.exception("Error in get_additional_metrics") - return {"error": str(e)} \ No newline at end of file + return {"error": str(e)} + + +def custom_is_finished_parser(response): + is_finished_list = [] + for g in response.flatten(): + resp = g.generations[0][0] + if resp.generation_info is not None: + if resp.generation_info.get("finish_reason") is not None: + is_finished_list.append( + resp.generation_info.get("finish_reason") == "STOP" + ) + + elif ( + isinstance(resp, ChatGeneration) + and t.cast(ChatGeneration, resp).message is not None + ): + resp_message: BaseMessage = t.cast(ChatGeneration, resp).message + if resp_message.response_metadata.get("finish_reason") is not None: + is_finished_list.append( + resp_message.response_metadata.get("finish_reason") == "STOP" + ) + else: + is_finished_list.append(True) + return all(is_finished_list) \ No newline at end of file diff --git a/frontend/src/components/ChatBot/ChatModesSwitch.tsx b/frontend/src/components/ChatBot/ChatModesSwitch.tsx index 5ff01a919..1327d5a7f 100644 --- a/frontend/src/components/ChatBot/ChatModesSwitch.tsx +++ b/frontend/src/components/ChatBot/ChatModesSwitch.tsx @@ -29,7 +29,7 @@ export default function ChatModesSwitch({ onClick={() => switchToOtherMode(currentModeIndex - 1)} ariaLabel='left' > - +
    switchToOtherMode(currentModeIndex + 1)} ariaLabel='right' > - + ); diff --git a/frontend/src/components/ChatBot/CommonChatActions.tsx b/frontend/src/components/ChatBot/CommonChatActions.tsx index d1a5c6243..9f7acc8b9 100644 --- a/frontend/src/components/ChatBot/CommonChatActions.tsx +++ b/frontend/src/components/ChatBot/CommonChatActions.tsx @@ -43,7 +43,7 @@ export default function CommonActions({ disabled={chat.isTyping || chat.isLoading} aria-label='copy text' > - + - {chat.speaking ? : } + {chat.speaking ? ( + + ) : ( + + )} ); diff --git a/frontend/src/components/ChatBot/MetricsTab.tsx b/frontend/src/components/ChatBot/MetricsTab.tsx index b39292d94..627c60ec3 100644 --- a/frontend/src/components/ChatBot/MetricsTab.tsx +++ b/frontend/src/components/ChatBot/MetricsTab.tsx @@ -119,23 +119,7 @@ function MetricsTab({ }} /> ), - PaginationNumericButton: ({ isSelected, innerProps, ...restProps }) => { - return ( - - ); - }, + Navigation: null, }} isKeyboardNavigable={false} /> diff --git a/frontend/src/components/ChatBot/MultiModeMetrics.tsx b/frontend/src/components/ChatBot/MultiModeMetrics.tsx index 8bd89f1d8..343664557 100644 --- a/frontend/src/components/ChatBot/MultiModeMetrics.tsx +++ b/frontend/src/components/ChatBot/MultiModeMetrics.tsx @@ -102,7 +102,7 @@ export default function MultiModeMetrics({ ), }), - columnHelper.accessor((row) => row.context_entity_recall_score as number, { + columnHelper.accessor((row) => row.context_entity_recall as number, { id: 'Entity Recall Score', cell: (info) => { const value = isNaN(info.getValue()) ? 'N.A' : info.getValue()?.toFixed(2); @@ -201,7 +201,7 @@ export default function MultiModeMetrics({ }); useEffect(() => { if (isWithAdditionalMetrics === false) { - table.setColumnVisibility({ 'Recall Score': false, 'Semantic Score': false, 'Rouge Score': false }); + table.setColumnVisibility({ 'Semantic Score': false, 'Rouge Score': false }); } else { table.resetColumnVisibility(true); } @@ -235,23 +235,7 @@ export default function MultiModeMetrics({ }} /> ), - PaginationNumericButton: ({ isSelected, innerProps, ...restProps }) => { - return ( - - ); - }, + Navigation: null, }} isKeyboardNavigable={false} /> From bad63890a61ffde89883dbfea928b05f2cc056d7 Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Thu, 5 Dec 2024 08:50:02 +0000 Subject: [PATCH 284/292] elementid if no id is there --- .../DeleteTabForOrphanNodes/index.tsx | 6 +++--- frontend/src/utils/Constants.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx index 5d23cc7c4..de8cdc186 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/DeleteTabForOrphanNodes/index.tsx @@ -122,13 +122,13 @@ export default function DeletePopUpForOrphanNodes({ return (
    handleOrphanNodeClick(info.row.id, 'chatInfoView'), - title: info.getValue(), + title: info.getValue() ? info.getValue() : info.row.id, }} > - {info.getValue()} + {info.getValue() ? info.getValue() : info.row.id}
    ); diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index d83000eca..2af5f9942 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -366,5 +366,5 @@ export const metricsinfo: Record = { answer_relevancy: "Determines How well the answer addresses the user's question.", rouge_score: 'Determines How much the generated answer matches the reference answer, word-for-word.', semantic_score: 'Determines How well the generated answer understands the meaning of the reference answer.', - context_entity_recall_score: 'Determines the recall of entities present in both generated answer and retrieved contexts', + context_entity_recall: 'Determines the recall of entities present in both generated answer and retrieved contexts', }; From 992fa9f2396eea400b263670fc9cc7f2906a94f4 Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Thu, 5 Dec 2024 10:06:32 +0000 Subject: [PATCH 285/292] backenapi for all env --- backend/score.py | 2 +- frontend/src/components/Layout/PageLayout.tsx | 90 ++++++++----------- 2 files changed, 40 insertions(+), 52 deletions(-) diff --git a/backend/score.py b/backend/score.py index cacbcc791..737a82afe 100644 --- a/backend/score.py +++ b/backend/score.py @@ -993,7 +993,7 @@ async def backend_connection_configuation(): message="Unable to connect backend DB" error_message = str(e) logging.exception(f'{error_message}') - return create_api_response(job_status, message=message, error=error_message + ' or fill from the login dialog', data=graph_connection) + return create_api_response(job_status, message=message, error=error_message.rstrip('.') + ', or fill from the login dialog.', data=graph_connection) finally: gc.collect() diff --git a/frontend/src/components/Layout/PageLayout.tsx b/frontend/src/components/Layout/PageLayout.tsx index 12cbc9cbe..ce37c50fc 100644 --- a/frontend/src/components/Layout/PageLayout.tsx +++ b/frontend/src/components/Layout/PageLayout.tsx @@ -63,12 +63,10 @@ const PageLayout: React.FC = () => { showDisconnectButton, } = useCredentials(); const { cancel } = useSpeechSynthesis(); - + useEffect(() => { async function initializeConnection() { const session = localStorage.getItem('neo4j.connection'); - const environment = process.env.VITE_ENV; - const isDev = environment === 'DEV'; // Fetch backend health status try { const response = await healthStatus(); @@ -137,63 +135,53 @@ const PageLayout: React.FC = () => { return false; } }; - // Handle case where session exists + // Handle connection initialization let backendApiResponse; try { - if (isDev) { - backendApiResponse = await envConnectionAPI(); - const connectionData = backendApiResponse.data; - const envCredentials = { - uri: connectionData.data.uri, - password: atob(connectionData.data.password), - userName: connectionData.data.user_name, - database: connectionData.data.database, - isReadonlyUser: !connectionData.data.write_access, - isGds: connectionData.data.gds_status, - }; - if (session && isDev) { - const updated = updateSessionIfNeeded(envCredentials, session); - if (!updated) { - setUserCredentialsFromSession(session); // Using stored session if no update is needed - } - setConnectionStatus(Boolean(connectionData.data.graph_connection)); - setIsBackendConnected(true); - handleDisconnectButtonState(false); - } else if (!session) { - setUserCredentials(envCredentials); - localStorage.setItem( - 'neo4j.connection', - JSON.stringify({ - uri: envCredentials.uri, - user: envCredentials.userName, - password: btoa(envCredentials.password), - database: envCredentials.database, - userDbVectorIndex: 384, - isReadOnlyUser: envCredentials.isReadonlyUser, - isGDS: envCredentials.isGds, - }) - ); - setConnectionStatus(true); - setGdsActive(envCredentials.isGds); - setIsReadOnlyUser(envCredentials.isReadonlyUser); - handleDisconnectButtonState(false); + backendApiResponse = await envConnectionAPI(); + const connectionData = backendApiResponse.data; + const envCredentials = { + uri: connectionData.data.uri, + password: atob(connectionData.data.password), + userName: connectionData.data.user_name, + database: connectionData.data.database, + isReadonlyUser: !connectionData.data.write_access, + isGds: connectionData.data.gds_status, + }; + if (session) { + const updated = updateSessionIfNeeded(envCredentials, session); + if (!updated) { + setUserCredentialsFromSession(session); // Use stored session if no update is needed } - } else if (session && !isDev) { - // For PROD, picking the session values - setUserCredentialsFromSession(session as string); - setConnectionStatus(true); - handleDisconnectButtonState(true); + setConnectionStatus(Boolean(connectionData.data.graph_connection)); + setIsBackendConnected(true); + handleDisconnectButtonState(false); } else { - setOpenConnection((prev) => ({ ...prev, openPopUp: true })); - handleDisconnectButtonState(true); + setUserCredentials(envCredentials); + localStorage.setItem( + 'neo4j.connection', + JSON.stringify({ + uri: envCredentials.uri, + user: envCredentials.userName, + password: btoa(envCredentials.password), + database: envCredentials.database, + userDbVectorIndex: 384, + isReadOnlyUser: envCredentials.isReadonlyUser, + isGDS: envCredentials.isGds, + }) + ); + setConnectionStatus(true); + setGdsActive(envCredentials.isGds); + setIsReadOnlyUser(envCredentials.isReadonlyUser); + handleDisconnectButtonState(false); } } catch (error) { - console.error('Error in DEV session handling:', error); + console.error('Error during backend API call:', error); if (session) { - setUserCredentialsFromSession(session as string); + setUserCredentialsFromSession(session); setConnectionStatus(true); } else { - setErrorMessage(backendApiResponse?.data.error); + setErrorMessage(backendApiResponse?.data?.error); setOpenConnection((prev) => ({ ...prev, openPopUp: true })); } handleDisconnectButtonState(true); From 7b3b1b4d29b5893b2e9af0f6efacfd2641ed928e Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Thu, 5 Dec 2024 18:08:30 +0530 Subject: [PATCH 286/292] Bug fixing for Icon (#924) * gds name handling * Update Content.tsx * show error message * format --- frontend/src/components/ChatBot/Chatbot.tsx | 12 ++++++------ frontend/src/components/ChatBot/chatInfo.ts | 3 +++ frontend/src/components/Layout/PageLayout.tsx | 4 ++-- .../GraphEnhancementDialog/Deduplication/index.tsx | 4 ++-- .../PostProcessingCheckList/SelectedJobList.tsx | 4 ++-- frontend/src/utils/Utils.ts | 2 +- 6 files changed, 16 insertions(+), 13 deletions(-) diff --git a/frontend/src/components/ChatBot/Chatbot.tsx b/frontend/src/components/ChatBot/Chatbot.tsx index aa84764bc..877dcdab4 100644 --- a/frontend/src/components/ChatBot/Chatbot.tsx +++ b/frontend/src/components/ChatBot/Chatbot.tsx @@ -249,7 +249,7 @@ const Chatbot: FC = (props) => { } else { setListMessages((prev) => prev.map((msg) => - (msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg) + msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg ) ); } @@ -264,7 +264,7 @@ const Chatbot: FC = (props) => { } else { setListMessages((prev) => prev.map((msg) => - (msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg) + msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg ) ); } @@ -273,7 +273,7 @@ const Chatbot: FC = (props) => { console.error(`API call failed for mode ${mode}:`, result.reason); setListMessages((prev) => prev.map((msg) => - (msg.id === chatbotMessageId + msg.id === chatbotMessageId ? { ...msg, modes: { @@ -281,7 +281,7 @@ const Chatbot: FC = (props) => { [mode]: { message: 'Failed to fetch response for this mode.', error: result.reason }, }, } - : msg) + : msg ) ); } @@ -294,7 +294,7 @@ const Chatbot: FC = (props) => { if (error instanceof Error) { setListMessages((prev) => prev.map((msg) => - (msg.id === chatbotMessageId + msg.id === chatbotMessageId ? { ...msg, isLoading: false, @@ -306,7 +306,7 @@ const Chatbot: FC = (props) => { }, }, } - : msg) + : msg ) ); } diff --git a/frontend/src/components/ChatBot/chatInfo.ts b/frontend/src/components/ChatBot/chatInfo.ts index c7e990ae7..26f2e765c 100644 --- a/frontend/src/components/ChatBot/chatInfo.ts +++ b/frontend/src/components/ChatBot/chatInfo.ts @@ -1,5 +1,6 @@ import { getNeighbors } from '../../services/GraphQuery'; import { NeoNode, NeoRelationship, UserCredentials } from '../../types'; +import { showNormalToast } from '../../utils/toasts'; export const handleGraphNodeClick = async ( userCredentials: UserCredentials, @@ -29,6 +30,8 @@ export const handleGraphNodeClick = async ( setNeoRels(relationships); setOpenGraphView(true); setViewPoint('chatInfoView'); + } else { + showNormalToast('No nodes or relationships found for the selected node.'); } } catch (error: any) { console.error('Error fetching neighbors:', error); diff --git a/frontend/src/components/Layout/PageLayout.tsx b/frontend/src/components/Layout/PageLayout.tsx index ce37c50fc..005d438b5 100644 --- a/frontend/src/components/Layout/PageLayout.tsx +++ b/frontend/src/components/Layout/PageLayout.tsx @@ -95,7 +95,7 @@ const PageLayout: React.FC = () => { password: atob(parsedConnection.password), database: parsedConnection.database, }); - setGdsActive(parsedConnection.isGDS); + setGdsActive(parsedConnection.isgdsActive); setIsReadOnlyUser(parsedConnection.isReadOnlyUser); } else { console.error('Invalid parsed session data:', parsedConnection); @@ -124,7 +124,7 @@ const PageLayout: React.FC = () => { database: envCredentials.database, userDbVectorIndex: 384, isReadOnlyUser: envCredentials.isReadonlyUser, - isGDS: envCredentials.isGds, + isgdsActive: envCredentials.isgdsActive, }) ); return true; diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx index d59b46e21..df30c25c1 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx @@ -104,12 +104,12 @@ export default function DeduplicationTab() { const onRemove = (nodeid: string, similarNodeId: string) => { setDuplicateNodes((prev) => { return prev.map((d) => - (d.e.elementId === nodeid + d.e.elementId === nodeid ? { ...d, similar: d.similar.filter((n) => n.elementId != similarNodeId), } - : d) + : d ); }); }; diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx index 447b1f846..fc5f39206 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx @@ -11,11 +11,11 @@ export default function SelectedJobList({ }) { const ongoingPostProcessingTasks = useMemo( () => - (isGdsActive + isGdsActive ? postProcessingTasks.includes('enable_communities') ? postProcessingTasks : postProcessingTasks.filter((s) => s != 'enable_communities') - : postProcessingTasks.filter((s) => s != 'enable_communities')), + : postProcessingTasks.filter((s) => s != 'enable_communities'), [isGdsActive, postProcessingTasks] ); return ( diff --git a/frontend/src/utils/Utils.ts b/frontend/src/utils/Utils.ts index 7314c55e7..82217535d 100644 --- a/frontend/src/utils/Utils.ts +++ b/frontend/src/utils/Utils.ts @@ -395,7 +395,7 @@ export const isFileCompleted = (waitingFile: CustomFile, item: SourceNode) => waitingFile && item.status === 'Completed'; export const calculateProcessedCount = (prev: number, batchSize: number) => - (prev === batchSize ? batchSize - 1 : prev + 1); + prev === batchSize ? batchSize - 1 : prev + 1; export const isProcessingFileValid = (item: SourceNode, userCredentials: UserCredentials) => { return item.status === 'Processing' && item.fileName != undefined && userCredentials && userCredentials.database; From fc85b45a3654d8e29f5169d84eacc6b5dcb1e23e Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Thu, 5 Dec 2024 13:09:09 +0000 Subject: [PATCH 287/292] diffbot placement --- frontend/src/components/Layout/PageLayout.tsx | 6 +++--- frontend/src/utils/Constants.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/Layout/PageLayout.tsx b/frontend/src/components/Layout/PageLayout.tsx index 005d438b5..cb29ceb01 100644 --- a/frontend/src/components/Layout/PageLayout.tsx +++ b/frontend/src/components/Layout/PageLayout.tsx @@ -146,7 +146,7 @@ const PageLayout: React.FC = () => { userName: connectionData.data.user_name, database: connectionData.data.database, isReadonlyUser: !connectionData.data.write_access, - isGds: connectionData.data.gds_status, + isgdsActive: connectionData.data.gds_status, }; if (session) { const updated = updateSessionIfNeeded(envCredentials, session); @@ -167,11 +167,11 @@ const PageLayout: React.FC = () => { database: envCredentials.database, userDbVectorIndex: 384, isReadOnlyUser: envCredentials.isReadonlyUser, - isGDS: envCredentials.isGds, + isgdsActive: envCredentials.isgdsActive, }) ); setConnectionStatus(true); - setGdsActive(envCredentials.isGds); + setGdsActive(envCredentials.isgdsActive); setIsReadOnlyUser(envCredentials.isReadonlyUser); handleDisconnectButtonState(false); } diff --git a/frontend/src/utils/Constants.ts b/frontend/src/utils/Constants.ts index 2af5f9942..d577194eb 100644 --- a/frontend/src/utils/Constants.ts +++ b/frontend/src/utils/Constants.ts @@ -13,12 +13,12 @@ export const llms = process.env?.VITE_LLM_MODELS?.trim() != '' ? (process.env.VITE_LLM_MODELS?.split(',') as string[]) : [ - 'diffbot', 'openai_gpt_3.5', 'openai_gpt_4o', 'openai_gpt_4o_mini', 'gemini_1.5_pro', 'gemini_1.5_flash', + 'diffbot', 'azure_ai_gpt_35', 'azure_ai_gpt_4o', 'ollama_llama3', From fac07e39dcf7baa34cda0a122e64bbafb4fedf85 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Thu, 5 Dec 2024 19:00:32 +0530 Subject: [PATCH 288/292] Update MultiModeMetrics.tsx --- frontend/src/components/ChatBot/MultiModeMetrics.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/ChatBot/MultiModeMetrics.tsx b/frontend/src/components/ChatBot/MultiModeMetrics.tsx index 343664557..5be629c1c 100644 --- a/frontend/src/components/ChatBot/MultiModeMetrics.tsx +++ b/frontend/src/components/ChatBot/MultiModeMetrics.tsx @@ -122,7 +122,7 @@ export default function MultiModeMetrics({ - Determines the recall of entities present in both reference and retrieved contexts. + Determines the recall of entities present in both generated answer and retrieved contexts. From 0fa4d84562e5909b6daa1013b3f31f73725cae75 Mon Sep 17 00:00:00 2001 From: aashipandya <156318202+aashipandya@users.noreply.github.com> Date: Thu, 5 Dec 2024 14:03:59 +0000 Subject: [PATCH 289/292] libmagic1 library added --- backend/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/Dockerfile b/backend/Dockerfile index 5249ac53c..c36f8ce2e 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -5,6 +5,7 @@ EXPOSE 8000 # Install dependencies and clean up in one layer RUN apt-get update && \ apt-get install -y --no-install-recommends \ + libmagic1 \ libgl1-mesa-glx \ libreoffice \ cmake \ From a86e07f0edc379b0ae3c85f9950e569e15e83aa7 Mon Sep 17 00:00:00 2001 From: Prakriti Solankey <156313631+prakriti-solankey@users.noreply.github.com> Date: Fri, 6 Dec 2024 11:51:58 +0530 Subject: [PATCH 290/292] Document read me update (#926) * removed openai, diffbot, groq key * Removed openai key, diffbot key from backend readme * Added openai key back * Update README.md * Update README.md Backend env change --------- Co-authored-by: kaustubh-darekar --- README.md | 20 +++++++++----------- backend/README.md | 6 +++--- backend/example.env | 3 +-- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index e37d3ddfe..6f222b44b 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Upload your files from local machine, GCS or S3 bucket or from web sources, choo - **Knowledge Graph Creation**: Transform unstructured data into structured knowledge graphs using LLMs. - **Providing Schema**: Provide your own custom schema or use existing schema in settings to generate graph. - **View Graph**: View graph for a particular source or multiple sources at a time in Bloom. -- **Chat with Data**: Interact with your data in a Neo4j database through conversational queries, also retrieve metadata about the source of response to your queries. +- **Chat with Data**: Interact with your data in a Neo4j database through conversational queries, also retrieve metadata about the source of response to your queries.For a dedicated chat interface, access the standalone chat application at: [Chat-Only](https://dev-frontend-dcavk67s4a-uc.a.run.app/chat-only). This link provides a focused chat experience for querying your data. ## Getting started @@ -37,12 +37,6 @@ EX: VITE_LLM_MODELS_PROD="openai_gpt_4o,openai_gpt_4o_mini,diffbot,gemini_1.5_flash" ``` -In your root folder, create a .env file with your OPENAI and DIFFBOT keys (if you want to use both): -```env -OPENAI_API_KEY="your-openai-key" -DIFFBOT_API_KEY="your-diffbot-key" -``` - if you only want OpenAI: ```env VITE_LLM_MODELS_PROD="diffbot,openai-gpt-3.5,openai-gpt-4o" @@ -102,9 +96,13 @@ Alternatively, you can run the backend and frontend separately: ``` - For the backend: -1. Create the backend/.env file by copy/pasting the backend/example.env. -2. Change values as needed -3. +1. Create the backend/.env file by copy/pasting the backend/example.env. To streamline the initial setup and testing of the application, you can preconfigure user credentials directly within the .env file. This bypasses the login dialog and allows you to immediately connect with a predefined user. + - **NEO4J_URI**: + - **NEO4J_USERNAME**: + - **NEO4J_PASSWORD**: + - **NEO4J_DATABASE**: +3. Change values as needed +4. ```bash cd backend python -m venv envName @@ -202,7 +200,7 @@ VITE_BACKEND_API_URL=${VITE_BACKEND_API_URL-backendurl} ## Usage -1. Connect to Neo4j Aura Instance which can be both AURA DS or AURA DB by passing URI and password or using Neo4j credentials file. +1. Connect to Neo4j Aura Instance which can be both AURA DS or AURA DB by passing URI and password through Backend env, fill using login dialog or drag and drop the Neo4j credentials file. 2. To differntiate we have added different icons. For AURA DB we have a database icon and for AURA DS we have scientific molecule icon right under Neo4j Connection details label. 3. Choose your source from a list of Unstructured sources to create graph. 4. Change the LLM (if required) from drop down, which will be used to generate graph. diff --git a/backend/README.md b/backend/README.md index 5783327d7..1ab091216 100644 --- a/backend/README.md +++ b/backend/README.md @@ -50,11 +50,11 @@ http://127.0.0.1:8000/redocs for ReDoc. ## Configuration -Update the environment variable in `.env` file. +Update the environment variable in `.env` file. Refer example.env in backend folder for more config. -`OPENAI_API_KEY`: Open AI key to use LLM +`OPENAI_API_KEY`: Open AI key to use incase of openai embeddings -`DIFFBOT_API_KEY` : Diffbot API key to use DiffbotGraphTransformer +`EMBEDDING_MODEL` : "all-MiniLM-L6-v2" or "openai" or "vertexai" `NEO4J_URI` : Neo4j URL diff --git a/backend/example.env b/backend/example.env index 7cf9b13ac..85b8d1054 100644 --- a/backend/example.env +++ b/backend/example.env @@ -1,6 +1,5 @@ OPENAI_API_KEY = "" -DIFFBOT_API_KEY = "" -GROQ_API_KEY = "" +#EMBEDDING_MODEL can be openai or vertexai or by default all-MiniLM-L6-v2 EMBEDDING_MODEL = "all-MiniLM-L6-v2" RAGAS_EMBEDDING_MODEL = "openai" IS_EMBEDDING = "true" From 98cfc3c1353feec43459b4d6749bf41973d99d82 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Mon, 9 Dec 2024 12:50:12 +0000 Subject: [PATCH 291/292] metric table and default model fixes --- .../src/components/ChatBot/ChatInfoModal.tsx | 8 +- frontend/src/components/ChatBot/Chatbot.tsx | 14 +- .../components/ChatBot/MultiModeMetrics.tsx | 153 +++++++++++++++--- frontend/src/components/FileTable.tsx | 1 + .../src/components/Layout/DrawerDropzone.tsx | 10 +- frontend/src/components/Layout/PageLayout.tsx | 2 +- .../Deduplication/index.tsx | 4 +- .../SelectedJobList.tsx | 4 +- .../src/components/UI/ButtonWithToolTip.tsx | 2 +- .../src/components/UI/IconButtonToolTip.tsx | 2 +- frontend/src/context/UsersFiles.tsx | 6 +- frontend/src/utils/Constants.ts | 2 +- frontend/src/utils/Utils.ts | 2 +- 13 files changed, 164 insertions(+), 46 deletions(-) diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index 68c07227d..ab66a52f1 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -96,16 +96,16 @@ const ChatInfoModal: React.FC = ({ const [enableReference, toggleReferenceVisibility] = useReducer((state: boolean) => !state, false); const textAreaRef = useRef(null); const [isAdditionalMetricsEnabled, setIsAdditionalMetricsEnabled] = useState( - multiModelMetrics.length > 0 && Object.keys(multiModelMetrics[0]).length > 3 + multiModelMetrics.length > 0 && Object.keys(multiModelMetrics[0]).length > 4 ? true - : multiModelMetrics.length > 0 && Object.keys(multiModelMetrics[0]).length <= 3 + : multiModelMetrics.length > 0 && Object.keys(multiModelMetrics[0]).length <= 4 ? false : null ); const [isAdditionalMetricsWithSingleMode, setIsAdditionalMetricsWithSingleMode] = useState( - metricDetails != undefined && Object.keys(metricDetails).length > 2 + metricDetails != undefined && Object.keys(metricDetails).length > 3 ? true - : metricDetails != undefined && Object.keys(metricDetails).length <= 2 + : metricDetails != undefined && Object.keys(metricDetails).length <= 3 ? false : null ); diff --git a/frontend/src/components/ChatBot/Chatbot.tsx b/frontend/src/components/ChatBot/Chatbot.tsx index 877dcdab4..a3fe174c2 100644 --- a/frontend/src/components/ChatBot/Chatbot.tsx +++ b/frontend/src/components/ChatBot/Chatbot.tsx @@ -249,7 +249,7 @@ const Chatbot: FC = (props) => { } else { setListMessages((prev) => prev.map((msg) => - msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg + (msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg) ) ); } @@ -264,7 +264,7 @@ const Chatbot: FC = (props) => { } else { setListMessages((prev) => prev.map((msg) => - msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg + (msg.id === chatbotMessageId ? { ...msg, modes: { ...msg.modes, [mode]: responseMode } } : msg) ) ); } @@ -273,7 +273,7 @@ const Chatbot: FC = (props) => { console.error(`API call failed for mode ${mode}:`, result.reason); setListMessages((prev) => prev.map((msg) => - msg.id === chatbotMessageId + (msg.id === chatbotMessageId ? { ...msg, modes: { @@ -281,7 +281,7 @@ const Chatbot: FC = (props) => { [mode]: { message: 'Failed to fetch response for this mode.', error: result.reason }, }, } - : msg + : msg) ) ); } @@ -294,7 +294,7 @@ const Chatbot: FC = (props) => { if (error instanceof Error) { setListMessages((prev) => prev.map((msg) => - msg.id === chatbotMessageId + (msg.id === chatbotMessageId ? { ...msg, isLoading: false, @@ -306,7 +306,7 @@ const Chatbot: FC = (props) => { }, }, } - : msg + : msg) ) ); } @@ -578,7 +578,7 @@ const Chatbot: FC = (props) => { }} onClose={() => setShowInfoModal(false)} isOpen={showInfoModal} - size={activeChat?.currentMode === chatModeLables['entity search+vector'] ? 'large' : 'medium'} + size={'large'} >
    Mode, footer: (info) => info.column.id, + maxSize: 150, }), columnHelper.accessor((row) => row.answer_relevancy as number, { id: 'Answer Relevancy', @@ -74,6 +75,7 @@ export default function MultiModeMetrics({ ), + maxSize: 150, }), columnHelper.accessor((row) => row.faithfulness as number, { id: 'Faithfullness', @@ -101,6 +103,7 @@ export default function MultiModeMetrics({ ), + maxSize: 150, }), columnHelper.accessor((row) => row.context_entity_recall as number, { id: 'Entity Recall Score', @@ -128,6 +131,7 @@ export default function MultiModeMetrics({ ), + maxSize: 150, }), columnHelper.accessor((row) => row.semantic_score as number, { id: 'Semantic Score', @@ -155,6 +159,7 @@ export default function MultiModeMetrics({ ), + maxSize: 150, }), columnHelper.accessor((row) => row.rouge_score as number, { id: 'Rouge Score', @@ -182,30 +187,134 @@ export default function MultiModeMetrics({ ), + maxSize: 150, }), ], [] ); - const table = useReactTable({ - data, - columns, - getCoreRowModel: getCoreRowModel(), - getFilteredRowModel: getFilteredRowModel(), - getPaginationRowModel: getPaginationRowModel(), - enableGlobalFilter: false, - autoResetPageIndex: false, - enableColumnResizing: true, - enableRowSelection: true, - enableMultiRowSelection: true, - enableSorting: false, - }); - useEffect(() => { - if (isWithAdditionalMetrics === false) { - table.setColumnVisibility({ 'Semantic Score': false, 'Rouge Score': false }); - } else { - table.resetColumnVisibility(true); - } - }, [isWithAdditionalMetrics, table]); + const columnswithoutSemanticAndRougeScores = useMemo( + () => [ + columnHelper.accessor((row) => row.mode, { + id: 'Mode', + cell: (info) => { + const metric = info.getValue(); + const capitilizedMetric = metric.includes('_') + ? metric + .split('_') + .map((w) => capitalize(w)) + .join(' ') + : capitalize(metric); + return ( +
    + {capitilizedMetric} +
    + ); + }, + header: () => Mode, + footer: (info) => info.column.id, + maxSize: 150, + }), + columnHelper.accessor((row) => row.answer_relevancy as number, { + id: 'Answer Relevancy', + cell: (info) => { + const value = isNaN(info.getValue()) ? 'N.A' : info.getValue()?.toFixed(2); + if (value === 'N.A') { + return ; + } + return {value}; + }, + header: () => ( + + Relevancy + + + + + + + + + Determines How well the answer addresses the user's question. + + + + + ), + }), + columnHelper.accessor((row) => row.faithfulness as number, { + id: 'Faithfullness', + cell: (info) => { + const value = isNaN(info.getValue()) ? 'N.A' : info.getValue()?.toFixed(2); + if (value === 'N.A') { + return ; + } + return {value}; + }, + header: () => ( + + Faithful + + + + + + + + + Determines How accurately the answer reflects the provided information. + + + + + ), + }), + columnHelper.accessor((row) => row.context_entity_recall as number, { + id: 'Entity Recall Score', + cell: (info) => { + const value = isNaN(info.getValue()) ? 'N.A' : info.getValue()?.toFixed(2); + if (value === 'N.A') { + return ; + } + return {value}; + }, + header: () => ( + + Context + + + + + + + + + Determines the recall of entities present in both generated answer and retrieved contexts. + + + + + ), + }), + ], + [] + ); + const config = useMemo( + () => ({ + data, + columns: !isWithAdditionalMetrics ? columnswithoutSemanticAndRougeScores : columns, + getCoreRowModel: getCoreRowModel(), + getFilteredRowModel: getFilteredRowModel(), + getPaginationRowModel: getPaginationRowModel(), + enableGlobalFilter: false, + autoResetPageIndex: false, + enableColumnResizing: true, + enableRowSelection: true, + enableMultiRowSelection: true, + enableSorting: false, + }), + [isWithAdditionalMetrics] + ); + const table = useReactTable(config); return ( @@ -226,7 +335,7 @@ export default function MultiModeMetrics({ }} isAutoResizingColumns={true} isLoading={metricsLoading} - rootProps={{ className: isWithAdditionalMetrics === false ? '!w-[465px]' : 'auto' }} + // rootProps={{ className: isWithAdditionalMetrics === false ? '!w-[465px]' : 'auto' }} components={{ Body: () => ( ((props, ref) => { return (
    = ({ return (
    - + {!isReadOnlyUser ? ( - + {alertState.showAlert && ( { showDisconnectButton, } = useCredentials(); const { cancel } = useSpeechSynthesis(); - + useEffect(() => { async function initializeConnection() { const session = localStorage.getItem('neo4j.connection'); diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx index df30c25c1..d59b46e21 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/Deduplication/index.tsx @@ -104,12 +104,12 @@ export default function DeduplicationTab() { const onRemove = (nodeid: string, similarNodeId: string) => { setDuplicateNodes((prev) => { return prev.map((d) => - d.e.elementId === nodeid + (d.e.elementId === nodeid ? { ...d, similar: d.similar.filter((n) => n.elementId != similarNodeId), } - : d + : d) ); }); }; diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx index fc5f39206..447b1f846 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/PostProcessingCheckList/SelectedJobList.tsx @@ -11,11 +11,11 @@ export default function SelectedJobList({ }) { const ongoingPostProcessingTasks = useMemo( () => - isGdsActive + (isGdsActive ? postProcessingTasks.includes('enable_communities') ? postProcessingTasks : postProcessingTasks.filter((s) => s != 'enable_communities') - : postProcessingTasks.filter((s) => s != 'enable_communities'), + : postProcessingTasks.filter((s) => s != 'enable_communities')), [isGdsActive, postProcessingTasks] ); return ( diff --git a/frontend/src/components/UI/ButtonWithToolTip.tsx b/frontend/src/components/UI/ButtonWithToolTip.tsx index 310566edf..acede505b 100644 --- a/frontend/src/components/UI/ButtonWithToolTip.tsx +++ b/frontend/src/components/UI/ButtonWithToolTip.tsx @@ -33,7 +33,7 @@ const ButtonWithToolTip = ({ const [isHovered, setIsHovered] = useState(false); return ( - +