Skip to content
Merged
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
4 changes: 2 additions & 2 deletions common/embeddings/embedding_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from common.logs.log import req_id_cv
from common.logs.logwriter import LogWriter
from common.metrics.prometheus_metrics import metrics
from common.utils.token_calculator import TokenCalculator
from common.utils.token_calculator import get_token_calculator

logger = logging.getLogger(__name__)

Expand All @@ -33,7 +33,7 @@ def __init__(self, config: dict, model_name: str):
self.embeddings = None
self.model_name = model_name
self.dimensions = config.get("dimensions", 1536)
self.token_calculator = TokenCalculator(token_limit=config.get("token_limit", 8192), model_name=model_name)
self.token_calculator = get_token_calculator(token_limit=config.get("token_limit", 8192), model_name=model_name)
LogWriter.info(
f"request_id={req_id_cv.get()} instantiated AI model_name={model_name} with dimensions={self.dimensions}"
)
Expand Down
2 changes: 1 addition & 1 deletion common/embeddings/tigergraph_embedding_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ def retrieve_similar_with_score(self, query_embedding, top_k=10, similarity_thre
}
)
end_time = time()
logger.info(f"Got {top_k} similar entries: {verts}")
# logger.info(f"Got {top_k} similar entries: {verts}")
similar = []
for r in verts:
if "results" in r:
Expand Down
6 changes: 4 additions & 2 deletions common/llm_services/base_llm.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,16 @@ def generate_gsql_prompt(self):
def route_response_prompt(self):
"""Property to get the prompt for the RouteResponse tool."""
prompt = """\
You are an expert at routing a user question to a vectorstore or function calls.
You are an expert at routing a user question to a vectorstore, function calls, or purely conversation history.
Use the conversation history for questions that are directly related to the conversation history.
Use the vectorstore for questions on that would be best suited by text documents.
Use the function calls for questions that ask about structured data, or operations on structured data.
Keep in mind that some questions about documents such as "how many documents are there?" can be answered by function calls.
The function calls can be used to answer questions about these entities: {v_types} and relationships: {e_types}.
Otherwise, use vectorstore. Give a binary choice 'functions' or 'vectorstore' based on the question.
Otherwise, use vectorstore. Choose one of 'functions', 'vectorstore', or 'history' based on the question and conversation history.
Return the a JSON with a single key 'datasource' and no premable or explaination.
Question to route: {question}
Conversation history: {conversation}
Format: {format_instructions}\
"""
return prompt
Expand Down
8 changes: 4 additions & 4 deletions common/prompts/aws_bedrock_claude3haiku/chatbot_response.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
You are a highly efficient and empathetic AI-powered knowledge graph assistant. Your goal is to provide accurate, helpful, and friendly response while maintaining professionalism.

Follow these guidelines:
- Give the context in JSON format contains key-context pairs, combine and rephrase it to answer the question.
- Use mostly the provided information in context without adding any reasoning or additional logic.
- Make sure all information in the provided context are covered in the generated answer, especially image references providing critical visual information.
- Give the contexts in JSON format contains key-context pairs, combine and rephrase it to answer the question.
- Score the contexts for their relevance to the question and use only the information of the high-scoring contexts without adding extra logic.
- Make sure most relevant information in the provided contexts are covered in the generated answer, especially image references providing critical visual information.
- Make sure to preserve the image links in markdown syntax "![description](url)" with its orignal format in the final answer if the context contains the links are used in the response. Do NOT modify or omit these image references.
- Use markdown syntax to geneate the answer, including title, paragraphs, bulleted or numbered list, images and tables if any, and place images or tables below the related text section.
- Ensure that each row of every table, including the header row, starts on a new line.
Expand All @@ -12,6 +12,6 @@ Follow these guidelines:
- Use the keys of the contexts used as citations if asked, DO NOT include citations in the final answer

Question: {question}
Context: {context}
Contexts: {context}
Query: {query}
Format: {format_instructions}
8 changes: 4 additions & 4 deletions common/prompts/google_gemini/chatbot_response.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
You are a highly efficient and empathetic AI-powered knowledge graph assistant. Your goal is to provide accurate, helpful, and friendly response while maintaining professionalism.

Follow these guidelines:
- Give the context in JSON format contains key-context pairs, combine and rephrase it to answer the question.
- Use mostly the provided information in context without adding any reasoning or additional logic.
- Make sure all information in the provided context are covered in the generated answer, especially image references providing critical visual information.
- Give the contexts in JSON format contains key-context pairs, combine and rephrase it to answer the question.
- Score the contexts for their relevance to the question and use only the information of the high-scoring contexts without adding extra logic.
- Make sure most relevant information in the provided contexts are covered in the generated answer, especially image references providing critical visual information.
- Make sure to preserve the image links in markdown syntax "![description](url)" with its orignal format in the final answer if the context contains the links are used in the response. Do NOT modify or omit these image references.
- Use markdown syntax to geneate the answer, including title, paragraphs, bulleted or numbered list, images and tables if any, and place images or tables below the related text section.
- Ensure that each row of every table, including the header row, starts on a new line.
Expand All @@ -12,6 +12,6 @@ Follow these guidelines:
- Use the keys of the contexts used as citations if asked, DO NOT include citations in the final answer

Question: {question}
Context: {context}
Contexts: {context}
Query: {query}
Format: {format_instructions}
8 changes: 4 additions & 4 deletions common/prompts/openai_gpt4/chatbot_response.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
You are a highly efficient and empathetic AI-powered knowledge graph assistant. Your goal is to provide accurate, helpful, and friendly response while maintaining professionalism.

Follow these guidelines:
- Give the context in JSON format contains key-context pairs, combine and rephrase it to answer the question.
- Use mostly the provided information in context without adding any reasoning or additional logic.
- Make sure all information in the provided context are covered in the generated answer, especially image references providing critical visual information.
- Give the contexts in JSON format contains key-context pairs, combine and rephrase it to answer the question.
- Score the contexts for their relevance to the question and use only the information of the high-scoring contexts without adding extra logic.
- Make sure most relevant information in the provided contexts are covered in the generated answer, especially image references providing critical visual information.
- Make sure to preserve the image links in markdown syntax "![description](url)" with its orignal format in the final answer if the context contains the links are used in the response. Do NOT modify or omit these image references.
- Use markdown syntax to geneate the answer, including title, paragraphs, bulleted or numbered list, images and tables if any, and place images or tables below the related text section.
- Ensure that each row of every table, including the header row, starts on a new line.
Expand All @@ -12,6 +12,6 @@ Follow these guidelines:
- Use the keys of the contexts used as citations if asked, DO NOT include citations in the final answer

Question: {question}
Context: {context}
Contexts: {context}
Query: {query}
Format: {format_instructions}
27 changes: 27 additions & 0 deletions common/utils/token_calculator.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,33 @@

logger = logging.getLogger(__name__)

# Cache for TokenCalculator instances to avoid re-initialization
_token_calculator_cache: dict[tuple[str, int], 'TokenCalculator'] = {}

def get_token_calculator(token_limit: int = 0, model_name: str = None) -> 'TokenCalculator':
"""
Factory function to get or create a TokenCalculator instance.
Reuses existing instances with the same model_name and token_limit to avoid re-initialization.

Args:
token_limit: Maximum number of tokens allowed for retrieved context
model_name: Name of the model to use for token counting

Returns:
TokenCalculator instance (cached if parameters match)
"""
model_name = model_name if model_name else "gpt-4"
token_limit = token_limit if token_limit else 0
cache_key = (model_name, token_limit)

if cache_key not in _token_calculator_cache:
_token_calculator_cache[cache_key] = TokenCalculator(token_limit=token_limit, model_name=model_name)
logger.debug(f"Created new TokenCalculator instance for model={model_name}, token_limit={token_limit}")
else:
logger.debug(f"Reusing cached TokenCalculator instance for model={model_name}, token_limit={token_limit}")

return _token_calculator_cache[cache_key]

class TokenCalculator:
"""Utility class for token counting and text truncation operations."""

Expand Down
1 change: 1 addition & 0 deletions graphrag-ui/.eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ module.exports = {
"warn",
{ allowConstantExport: true },
],
"no-trailing-spaces": ["error", { "skipBlankLines": false }],
},
};
81 changes: 70 additions & 11 deletions graphrag-ui/src/actions/ActionProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,10 @@ const ActionProvider: React.FC<ActionProviderProps> = ({
const creds = localStorage.getItem("creds");
console.log("Sending credentials, length:", creds ? creds.length : 0);
queryGraphragWs2(creds!);

// Send RAG pattern
//sendMessage(selectedRagPattern);

// Send conversation ID (or "new" for new conversation)
const conversationId = conversationManager.getCurrentConversationId();
const conversationIdToSend = conversationId || "new";
Expand All @@ -113,22 +113,76 @@ const ActionProvider: React.FC<ActionProviderProps> = ({
},
});

// Initialize conversation manager with any existing conversation data
// Initialize conversation manager and load conversation messages
useEffect(() => {
const selectedConversationData = localStorage.getItem('selectedConversationData');
if (selectedConversationData) {
try {
const data = JSON.parse(selectedConversationData);
// Extract conversation ID from the first message
if (data.messages && data.messages.length > 0) {
const conversationId = data.messages[0].conversation_id;

// Handle different data structures
let messages: any[] = [];
let conversationId: string | null = null;

if (Array.isArray(data) && data.length > 0) {
// Direct array of messages from API
messages = data;
conversationId = data[0].conversation_id;
} else if (data.messages && Array.isArray(data.messages)) {
// Wrapped in messages property
messages = data.messages;
conversationId = data.messages[0]?.conversation_id;
} else if (data.content && Array.isArray(data.content)) {
// Wrapped in content property (from fetchHistory2)
messages = data.content;
conversationId = data.conversation_id || data.content[0]?.conversation_id;
}

if (conversationId) {
conversationManager.setCurrentConversationId(conversationId);
}

// Load conversation messages into the chat UI
// Sort messages by timestamp if available to maintain chronological order
const sortedMessages = [...messages].sort((a: any, b: any) => {
const timeA = a.create_ts ? new Date(a.create_ts).getTime() : 0;
const timeB = b.create_ts ? new Date(b.create_ts).getTime() : 0;
return timeA - timeB; // Oldest first
});

const loadedMessages: any[] = [];

sortedMessages.forEach((msg: any) => {
if (msg.role === "user") {
// Create user message
const userMessage = createClientMessage(msg.content || "", {
delay: 0,
});
loadedMessages.push(userMessage);
} else if (msg.role === "system") {
// Create bot message
const botMessage = createChatBotMessage({
content: msg.content || "",
response_type: msg.response_type || "text",
query_sources: msg.query_sources,
answered_question: msg.answered_question,
});
loadedMessages.push(botMessage);
}
});

// Set the loaded messages in the chat state
if (loadedMessages.length > 0) {
setState((prev: any) => ({
...prev,
messages: loadedMessages,
}));
}
} catch (error) {
console.error("Error parsing conversation data:", error);
// Silently handle error parsing conversation data
}
}
}, []);
}, [createChatBotMessage, createClientMessage, setState]);

// eslint-disable-next-line
// @ts-ignore
Expand Down Expand Up @@ -168,6 +222,10 @@ const ActionProvider: React.FC<ActionProviderProps> = ({
...prev,
messages: [...prev.messages, loading],
}));

// Dispatch event to refresh conversation list when user sends a question
// This ensures the side menu updates when a new message is sent
window.dispatchEvent(new CustomEvent('conversationUpdated'));
};

// FOR REFERENCE
Expand Down Expand Up @@ -200,16 +258,17 @@ const ActionProvider: React.FC<ActionProviderProps> = ({
useEffect(() => {
if (lastMessage !== null) {
setMessageHistory((prev) => prev.concat(lastMessage));

try {
const messageData = JSON.parse(lastMessage.data);

// Check if this is a conversation ID message (first message from backend)
if (messageData.conversation_id && !messageData.content) {
conversationManager.setCurrentConversationId(messageData.conversation_id);
// Don't dispatch refresh event here - refresh happens when user sends the question
return; // Don't create a bot message for conversation ID
}

// Handle regular bot messages
const botMessage = createChatBotMessage(messageData);
setState((prev) => {
Expand Down
Loading
Loading