Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
302 changes: 277 additions & 25 deletions common/config.py

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions common/embeddings/embedding_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,9 +184,9 @@ class VertexAI_PaLM_Embedding(EmbeddingModel):

def __init__(self, config):
super().__init__(config, model_name=config.get("model_name", "VertexAI PaLM"))
from langchain.embeddings import VertexAIEmbeddings
from langchain_google_vertexai import VertexAIEmbeddings

self.embeddings = VertexAIEmbeddings(model_name=self.model_name)
self.embeddings = VertexAIEmbeddings(model=self.model_name)


class GenAI_Embedding(EmbeddingModel):
Expand Down Expand Up @@ -243,3 +243,4 @@ def __init__(self, config):
model=self.model_name,
base_url=base_url
)

5 changes: 3 additions & 2 deletions common/llm_services/google_vertexai_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
class GoogleVertexAI(LLM_Model):
def __init__(self, config):
super().__init__(config)
from langchain_community.llms import VertexAI
from langchain_google_vertexai import VertexAI

model_name = config["llm_model"]
self.llm = VertexAI(
model_name=model_name, max_output_tokens=1000, **config["model_kwargs"]
model=model_name, max_output_tokens=1000, **config["model_kwargs"]
)

self.prompt_path = config["prompt_path"]
Expand All @@ -38,3 +38,4 @@ def entity_relationship_extraction_prompt(self):
@property
def model(self):
return self.llm

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
You are a helpful assistant responsible for generating a comprehensive summary of the data provided below.
Given one or two entities, and a list of descriptions, all related to the same entity or group of entities.
Please concatenate all of these into a single, comprehensive description. Make sure to include information collected from all the descriptions.
If the provided descriptions are contradictory, please resolve the contradictions and provide a single, coherent summary, but do not add any information that is not in the description.
Make sure it is written in third person, and include the entity names so we the have full context.

#######
-Data-
Commuinty Title: {entity_name}
Description List: {description_list}

11 changes: 11 additions & 0 deletions common/prompts/custom/aml/community_summarization.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
You are a helpful assistant responsible for generating a comprehensive summary of the data provided below.
Given one or two entities, and a list of descriptions, all related to the same entity or group of entities.
Please concatenate all of these into a single, comprehensive description. Make sure to include information collected from all the descriptions.
If the provided descriptions are contradictory, please resolve the contradictions and provide a single, coherent summary, but do not add any information that is not in the description.
Make sure it is written in third person, and include the entity names so we the have full context.

#######
-Data-
Commuinty Title: {entity_name}
Description List: {description_list}

11 changes: 11 additions & 0 deletions common/prompts/gcp_vertexai_palm/community_summarization.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
You are a helpful assistant responsible for generating a comprehensive summary of the data provided below.
Given one or two entities, and a list of descriptions, all related to the same entity or group of entities.
Please concatenate all of these into a single, comprehensive description. Make sure to include information collected from all the descriptions.
If the provided descriptions are contradictory, please resolve the contradictions and provide a single, coherent summary, but do not add any information that is not in the description.
Make sure it is written in third person, and include the entity names so we the have full context.

#######
-Data-
Commuinty Title: {entity_name}
Description List: {description_list}

11 changes: 11 additions & 0 deletions common/prompts/google_gemini/community_summarization.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
You are a helpful assistant responsible for generating a comprehensive summary of the data provided below.
Given one or two entities, and a list of descriptions, all related to the same entity or group of entities.
Please concatenate all of these into a single, comprehensive description. Make sure to include information collected from all the descriptions.
If the provided descriptions are contradictory, please resolve the contradictions and provide a single, coherent summary, but do not add any information that is not in the description.
Make sure it is written in third person, and include the entity names so we the have full context.

#######
-Data-
Commuinty Title: {entity_name}
Description List: {description_list}

11 changes: 11 additions & 0 deletions common/prompts/openai_gpt4/community_summarization.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
You are a helpful assistant responsible for generating a comprehensive summary of the data provided below.
Given one or two entities, and a list of descriptions, all related to the same entity or group of entities.
Please concatenate all of these into a single, comprehensive description. Make sure to include information collected from all the descriptions.
If the provided descriptions are contradictory, please resolve the contradictions and provide a single, coherent summary, but do not add any information that is not in the description.
Make sure it is written in third person, and include the entity names so we the have full context.

#######
-Data-
Commuinty Title: {entity_name}
Description List: {description_list}

1 change: 1 addition & 0 deletions common/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ kiwisolver==1.4.8
langchain>=0.3.26
langchain-core>=0.3.26
langchain_google_genai==2.1.8
langchain-google-vertexai==2.1.2
langchain-community==0.3.26
langchain-experimental==0.3.5rc1
langchain-groq==0.3.4
Expand Down
10 changes: 10 additions & 0 deletions docs/tutorials/configs/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ server {
proxy_pass http://graphrag-ui:3000/;
}

location /setup {
rewrite ^/setup$ / break;
proxy_pass http://graphrag-ui:3000;
}

location /setup/ {
rewrite ^/setup/.*$ / break;
proxy_pass http://graphrag-ui:3000;
}


location /chat-dialog {
proxy_pass http://graphrag-ui:3000/;
Expand Down
43 changes: 23 additions & 20 deletions ecc/app/ecc_util.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from common.chunkers import character_chunker, regex_chunker, semantic_chunker, markdown_chunker, recursive_chunker, html_chunker, single_chunker
from common.config import graphrag_config, embedding_service, llm_config
from common.config import graphrag_config, embedding_service, llm_config, get_completion_config
from common.llm_services import (
AWS_SageMaker_Endpoint,
AWSBedrock,
Expand Down Expand Up @@ -55,24 +55,27 @@ def get_chunker(chunker_type: str = ""):
return chunker


def get_llm_service():
if llm_config["completion_service"]["llm_service"].lower() == "openai":
llm_provider = OpenAI(llm_config["completion_service"])
elif llm_config["completion_service"]["llm_service"].lower() == "azure":
llm_provider = AzureOpenAI(llm_config["completion_service"])
elif llm_config["completion_service"]["llm_service"].lower() == "sagemaker":
llm_provider = AWS_SageMaker_Endpoint(llm_config["completion_service"])
elif llm_config["completion_service"]["llm_service"].lower() == "vertexai":
llm_provider = GoogleVertexAI(llm_config["completion_service"])
elif llm_config["completion_service"]["llm_service"].lower() == "genai":
llm_provider = GoogleGenAI(llm_config["completion_service"])
elif llm_config["completion_service"]["llm_service"].lower() == "bedrock":
llm_provider = AWSBedrock(llm_config["completion_service"])
elif llm_config["completion_service"]["llm_service"].lower() == "groq":
llm_provider = Groq(llm_config["completion_service"])
elif llm_config["completion_service"]["llm_service"].lower() == "ollama":
llm_provider = Ollama(llm_config["completion_service"])
elif llm_config["completion_service"]["llm_service"].lower() == "huggingface":
llm_provider = HuggingFaceEndpoint(llm_config["completion_service"])
def get_llm_service(graphname=None):
config = get_completion_config(graphname)
if config["llm_service"].lower() == "openai":
llm_provider = OpenAI(config)
elif config["llm_service"].lower() == "azure":
llm_provider = AzureOpenAI(config)
elif config["llm_service"].lower() == "sagemaker":
llm_provider = AWS_SageMaker_Endpoint(config)
elif config["llm_service"].lower() == "vertexai":
llm_provider = GoogleVertexAI(config)
elif config["llm_service"].lower() == "genai":
llm_provider = GoogleGenAI(config)
elif config["llm_service"].lower() == "bedrock":
llm_provider = AWSBedrock(config)
elif config["llm_service"].lower() == "groq":
llm_provider = Groq(config)
elif config["llm_service"].lower() == "ollama":
llm_provider = Ollama(config)
elif config["llm_service"].lower() == "huggingface":
llm_provider = HuggingFaceEndpoint(config)
else:
raise Exception("LLM Completion Service Not Supported")

return llm_provider
45 changes: 32 additions & 13 deletions ecc/app/graphrag/community_summarizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,45 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import re
import logging

from langchain_core.prompts import PromptTemplate

from common.llm_services import LLM_Model
from common.py_schemas import CommunitySummary
from common.config import completion_config

logger = logging.getLogger(__name__)


# Load prompt from file
def load_community_prompt():
prompt_path = completion_config.get("prompt_path", "./common/prompts/openai_gpt4/")
if prompt_path.startswith("./"):
prompt_path = prompt_path[2:]
prompt_path = prompt_path.rstrip("/")

prompt_file = os.path.join(prompt_path, "community_summarization.txt")
if not os.path.exists(prompt_file):
error_msg = f"Community summarization prompt file not found: {prompt_file}. Please ensure the file exists in the configured prompt path."
logger.error(error_msg)
raise FileNotFoundError(error_msg)

try:
with open(prompt_file, "r", encoding="utf-8") as f:
content = f.read()
logger.info(f"Successfully loaded community summarization prompt from: {prompt_file}")
return content
except Exception as e:
error_msg = f"Failed to read community summarization prompt from {prompt_file}: {str(e)}"
logger.error(error_msg)
raise Exception(error_msg)


# src: https://github.com/microsoft/graphrag/blob/main/graphrag/index/graph/extractors/summarize/prompts.py
SUMMARIZE_PROMPT = PromptTemplate.from_template("""
You are a helpful assistant responsible for generating a comprehensive summary of the data provided below.
Given one or two entities, and a list of descriptions, all related to the same entity or group of entities.
Please concatenate all of these into a single, comprehensive description. Make sure to include information collected from all the descriptions.
If the provided descriptions are contradictory, please resolve the contradictions and provide a single, coherent summary, but do not add any information that is not in the description.
Make sure it is written in third person, and include the entity names so we the have full context.

#######
-Data-
Commuinty Title: {entity_name}
Description List: {description_list}
""")
SUMMARIZE_PROMPT = PromptTemplate.from_template(load_community_prompt())

id_pat = re.compile(r"[_\d]*")

Expand All @@ -58,4 +77,4 @@ async def summarize(self, name: str, text: list[str]) -> CommunitySummary:
)
except Exception as e:
return {"error": True, "summary": "", "message": str(e)}
return {"error": False, "summary": summary.summary}
return {"error": False, "summary": summary.summary}
2 changes: 1 addition & 1 deletion ecc/app/graphrag/workers.py
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ async def process_community(
if len(children) == 1:
summary = children[0]
else:
llm = ecc_util.get_llm_service()
llm = ecc_util.get_llm_service(conn.graphname)
summarizer = community_summarizer.CommunitySummarizer(llm)
summary = await summarizer.summarize(comm_id, children)
if summary["error"]:
Expand Down
47 changes: 47 additions & 0 deletions ecc/app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
embedding_service,
get_llm_service,
llm_config,
reload_db_config,
)
from common.db.connections import elevate_db_connection_to_token, get_db_connection_id_token
from common.embeddings.base_embedding_store import EmbeddingStore
Expand Down Expand Up @@ -213,6 +214,41 @@ async def run_with_tracking(task_key: str, run_func, graphname: str, conn):
try:
running_tasks[task_key] = {"status": "running", "started_at": time.time()}
LogWriter.info(f"Starting ECC task: {task_key}")

# Reload config at the start of each job to ensure latest settings are used
LogWriter.info("📥 Reloading configuration for new job...")
from common.config import reload_llm_config, reload_graphrag_config, reload_db_config

llm_result = reload_llm_config()
if llm_result["status"] == "success":
LogWriter.info(f"✅ LLM config reloaded: {llm_result['message']}")
completion_service = llm_config.get("completion_service", {})
ecc_model = completion_service.get("llm_model", "unknown")
ecc_provider = completion_service.get("llm_service", "unknown")
LogWriter.info(
f"[ECC] Using completion model={ecc_model} (provider={ecc_provider})"
)
else:
LogWriter.warning(f"⚠️ LLM config reload had issues: {llm_result['message']}")

db_result = reload_db_config()
if db_result["status"] == "success":
LogWriter.info(
f"✅ DB config reloaded: {db_result['message']} "
f"(host={db_config.get('hostname')}, "
f"restppPort={db_config.get('restppPort')}, "
f"gsPort={db_config.get('gsPort')})"
)
else:
LogWriter.warning(f"⚠️ DB config reload had issues: {db_result['message']}")

graphrag_result = reload_graphrag_config()
if graphrag_result["status"] == "success":
LogWriter.info(f"✅ GraphRAG config reloaded: {graphrag_result['message']}")
else:
LogWriter.warning(f"⚠️ GraphRAG config reload had issues: {graphrag_result['message']}")

# Now run the actual job with fresh config
await run_func(graphname, conn)
running_tasks[task_key] = {"status": "completed", "completed_at": time.time()}
LogWriter.info(f"Completed ECC task: {task_key}")
Expand Down Expand Up @@ -242,6 +278,17 @@ def consistency_update(
response: Response,
credentials = Depends(auth_credentials),
):
db_result = reload_db_config()
if db_result["status"] == "success":
LogWriter.info(
f"✅ DB config reloaded: {db_result['message']} "
f"(host={db_config.get('hostname')}, "
f"restppPort={db_config.get('restppPort')}, "
f"gsPort={db_config.get('gsPort')})"
)
else:
LogWriter.warning(f"⚠️ DB config reload had issues: {db_result['message']}")

if isinstance(credentials, HTTPBasicCredentials):
conn = elevate_db_connection_to_token(
db_config.get("hostname"),
Expand Down
1 change: 1 addition & 0 deletions graphrag-ui/src/components/Bot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ const Bot = ({ layout, getConversationId }: { layout?: string | undefined, getCo
const handleSelect = (value) => {
setSelectedGraph(value);
localStorage.setItem("selectedGraph", value);
window.dispatchEvent(new Event("graphrag:selectedGraph"));
navigate("/chat");
//window.location.reload();
};
Expand Down
Loading
Loading