Skip to content

Commit

Permalink
Merge pull request #203 from tigergraph/GML-1737-ui_integration
Browse files Browse the repository at this point in the history
Gml 1737 UI integration
  • Loading branch information
RobRossmiller-TG authored Jun 14, 2024
2 parents bd176c2 + 6b58ae4 commit 7858a2e
Show file tree
Hide file tree
Showing 47 changed files with 1,551 additions and 3,391 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,6 @@ copilot/tests/logs/*
volumes
build/
/k8s
run.sh
configs
venv
3 changes: 1 addition & 2 deletions chat-history/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM golang:1.22.3 as builder

WORKDIR app
WORKDIR /app
COPY . .
RUN go mod download
RUN go build -v -o server
Expand All @@ -19,7 +19,6 @@ RUN set -x && apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -
# Copy the binary to the production image from the builder stage.
COPY --from=builder /app/server server

EXPOSE 8000

CMD ["./server"]

24 changes: 18 additions & 6 deletions chat-history/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package config

import (
"encoding/json"
"fmt"
"os"
)

Expand All @@ -10,10 +11,10 @@ type LLMConfig struct {
}

type DbConfig struct {
Port string `json:"apiPort"`
DbPath string `json:"dbPath"`
Port string `json:"apiPort"`
DbPath string `json:"dbPath"`
DbLogPath string `json:"dbLogPath"`
LogPath string `json:"logPath"`
LogPath string `json:"logPath"`
// DbHostname string `json:"hostname"`
// Username string `json:"username"`
// Password string `json:"password"`
Expand All @@ -29,9 +30,20 @@ type Config struct {
}

func LoadConfig(path string) (Config, error) {
b, err := os.ReadFile(path)
if err != nil {
return Config{}, err
var b []byte
if _, err := os.Stat(path); os.IsNotExist(err) {
// file doesn't exist read from env
cfg := os.Getenv("CONFIG")
if cfg == "" {
fmt.Println("CONFIG path is not found nor is the CONFIG json env variable defined")
os.Exit(1)
}
b = []byte(cfg)
} else {
b, err = os.ReadFile(path)
if err != nil {
return Config{}, err
}
}

var cfg Config
Expand Down
27 changes: 24 additions & 3 deletions chat-history/db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package db
import (
"chat-history/middleware"
"chat-history/structs"
"errors"
"log"
"os"
"strings"
Expand Down Expand Up @@ -98,11 +99,31 @@ func UpdateConversationById(message structs.Message) (*structs.Conversation, err
mu.Lock()
defer mu.Unlock()

if result := db.Create(&message); result.Error != nil {
return nil, result.Error
// Find the existing message by conversation ID and message ID
var existingMessage structs.Message
tx := db.Where("conversation_id = ? AND message_id = ? ", message.ConversationId, message.MessageId).First(&existingMessage)
if tx.Error != nil {
if errors.Is(tx.Error, gorm.ErrRecordNotFound) {
if result := db.Create(&message); result.Error != nil {
return nil, result.Error
}
} else {
return nil, tx.Error
}
} else {
// Update only the feedback and comments fields if the message exists
if result := db.Model(&existingMessage).Select("Feedback", "Comment").Updates(
structs.Message{
Feedback: message.Feedback,
Comment: message.Comment,
}); result.Error != nil {
return nil, result.Error
}
}

// Retrieve the updated conversation
convo := structs.Conversation{}
tx := db.Where("conversation_id = ?", message.ConversationId).Find(&convo)
tx = db.Where("conversation_id = ?", message.ConversationId).Find(&convo)

if err := tx.Error; err != nil {
return nil, err
Expand Down
67 changes: 67 additions & 0 deletions chat-history/db/db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,73 @@ func TestGetUserConversationById(t *testing.T) {
}
}

func TestUpdateUserConversationById(t *testing.T) {
setupTest(t, true)
convoId := "601529eb-4927-4e24-b285-bd6b9519a951"
messages := GetUserConversationById(USER, convoId)

if len(messages) == 0 {
t.Fatalf("Messages should not be empty for conversation ID: %s", convoId)
}

originalMessage := messages[0]
updatedComment := "Updated comment"

// Prepare the updated message
updatedMessage := structs.Message{
ConversationId: originalMessage.ConversationId,
MessageId: originalMessage.MessageId,
Feedback: structs.ThumbsUp,
Comment: updatedComment,
}

// Call the UpdateConversationById function
_, err := UpdateConversationById(updatedMessage)
if err != nil {
t.Fatalf("Failed to update conversation: %v", err)
}

// Retrieve the updated messages
updatedMessages := GetUserConversationById(USER, convoId)
if len(updatedMessages) == 0 {
t.Fatalf("Updated messages should not be empty for conversation ID: %s", convoId)
}

// Validate the updated message fields
for _, m := range updatedMessages {
if m.MessageId == originalMessage.MessageId {
if m.Feedback != structs.ThumbsUp {
t.Fatalf("Expected feedback to be %d, got %d", structs.ThumbsUp, m.Feedback)
}
if m.Comment != updatedComment {
t.Fatalf("Expected comment to be '%s', got '%s'", updatedComment, m.Comment)
}
// Ensure other fields are not affected
if m.ConversationId != originalMessage.ConversationId {
t.Fatalf("Expected conversation ID to be '%s', got '%s'", originalMessage.ConversationId, m.ConversationId)
}
if m.MessageId != originalMessage.MessageId {
t.Fatalf("Expected message ID to be '%s', got '%s'", originalMessage.MessageId, m.MessageId)
}
if m.ParentId != originalMessage.ParentId {
t.Fatalf("Expected parent ID to be '%v', got '%v'", originalMessage.ParentId, m.ParentId)
}
if m.ModelName != originalMessage.ModelName {
t.Fatalf("Expected model name to be '%s', got '%s'", originalMessage.ModelName, m.ModelName)
}
if m.Content != originalMessage.Content {
t.Fatalf("Expected content to be '%s', got '%s'", originalMessage.Content, m.Content)
}
if m.Role != originalMessage.Role {
t.Fatalf("Expected role to be '%s', got '%s'", originalMessage.Role, m.Role)
}
if m.ResponseTime != originalMessage.ResponseTime {
t.Fatalf("Expected response time to be '%f', got '%f'", originalMessage.ResponseTime, m.ResponseTime)
}
}
}
}

// parallel tests
func TestParallelWrites(t *testing.T) {
/*
Expand Down
3 changes: 2 additions & 1 deletion chat-history/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import (
)

func main() {
config, err := config.LoadConfig("config.json")
configPath:= os.Getenv("CONFIG")
config, err := config.LoadConfig(configPath)
if err != nil {
panic(err)
}
Expand Down
5 changes: 3 additions & 2 deletions chat-history/structs/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ type Message struct {
ModelName string `json:"model"`
Content string `json:"content"`
Role MessagengerRole `json:"role"`
Feedback Feedback `json:"feedback"`
ResponseTime float64 `json:"response_time"`
Feedback Feedback `json:"feedback"`// time in fractional seconds (i.e., 1.25 seconds)
Comment string `json:"comment"`
}

Expand All @@ -64,7 +65,7 @@ func (m Message) String() string {
MessageId %v
ParentId %v
`,
m.ID,m.UpdatedAt, m.ConversationId, m.MessageId, m.ParentId,)
m.ID, m.UpdatedAt, m.ConversationId, m.MessageId, m.ParentId)
return fmt.Sprintf(`
ID %v
ConversationId %v
Expand Down
20 changes: 19 additions & 1 deletion common/db/connections.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,24 @@ def get_db_connection_pwd(
return conn



def get_db_connection_pwd_manual(
graphname, username: str, password: str,
) -> TigerGraphConnectionProxy:
"""
Manual auth - pass in user/pass not from basic auth
"""
conn = elevate_db_connection_to_token(
db_config["hostname"], username, password, graphname
)

conn.customizeHeader(
timeout=db_config["default_timeout"] * 1000, responseSize=5000000
)
conn = TigerGraphConnectionProxy(conn)
LogWriter.info("Connected to TigerGraph with password")
return conn

def elevate_db_connection_to_token(host, username, password, graphname) -> TigerGraphConnectionProxy:
conn = TigerGraphConnection(
host=host,
Expand Down Expand Up @@ -106,4 +124,4 @@ def elevate_db_connection_to_token(host, username, password, graphname) -> Tiger
apiToken=apiToken
)

return conn
return conn
2 changes: 2 additions & 0 deletions common/prompts/aws_bedrock_claude3haiku/generate_function.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
Use the vertex types, edge types, and their attributes and IDs below to write the pyTigerGraph function call to answer the question using a pyTigerGraph connection.
When the question asks for "How many", make sure to select a function that contains "Count" in the description/function call. Make sure never to generate a function that is not listed below.
When certain entities are mapped to vertex attributes, may consider to generate a WHERE clause.
If a WHERE clause is generated, please follow the instruction with proper quoting. To construct a WHERE clause string. Ensure that string attribute values are properly quoted.
For example, if the generated function is "conn.getVertices('Person', where='name=William Torres')", Expected Output: "conn.getVertices('Person', where='name="William Torres"')", This rule applies to all types of attributes. e.g., name, email, address and so on.
Documentation contains helpful Python docstrings for the various functions. Use this knowledge to construct the proper function call. Choose one function to execute.
Don't generate target_vertex_ids if there is no the term 'id' explicitly mentioned in the question.
Vertex Types: {vertex_types}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
Replace the entites mentioned in the question to one of these choices: {vertices}.
Choose a better mapping between vertex type or its attributes: {verticesAttrs}.
Replace the entites mentioned in the question to one of these choices: {vertices}.
If an entity, such as "John Doe", is mentioned multiple times in the conversation but is referred to by different names or pronouns (e.g., "Joe", "he"),
always use the most complete identifier for that entity throughout the question. In this example, use "John Doe" as the entity. Choose a better mapping between vertex type or its attributes: {verticesAttrs}.
Replace the relationships mentioned in the question to one of these choices: {edges}.
Make sure the entities are either the source vertices or target vertices of the relationships: {edgesInfo}.
When certain entities are mapped to vertex attributes, may consider to generate a WHERE clause.
Expand Down
2 changes: 2 additions & 0 deletions common/prompts/aws_bedrock_titan/generate_function.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
Use the vertex types, edge types, and their attributes and IDs to write the pyTigerGraph function call to answer the question using a pyTigerGraph connection.
When certain entities are mapped to vertex attributes, may consider to generate a WHERE clause.
If a WHERE clause is generated, please follow the instruction with proper quoting. To construct a WHERE clause string. Ensure that string attribute values are properly quoted.
For example, if the generated function is "conn.getVertices('Person', where='name=William Torres')", Expected Output: "conn.getVertices('Person', where='name="William Torres"')", This rule applies to all types of attributes. e.g., name, email, address and so on.
Documentation contains helpful Python docstrings for the various functions. Use this knowledge to construct the proper function call. Choose one function to execute.
Don't generate target_vertex_ids if there is no the term 'id' explicitly mentioned in the question.
Vertex Types: {vertices}
Expand Down
4 changes: 3 additions & 1 deletion common/prompts/aws_bedrock_titan/map_question_to_schema.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
Replace the entites mentioned in the question to one of these choices: {vertices}.
Replace the entites mentioned in the question to one of these choices: {vertices}.
If an entity, such as "John Doe", is mentioned multiple times in the conversation but is referred to by different names or pronouns (e.g., "Joe", "he"),
always use the most complete identifier for that entity throughout the question. In this example, use "John Doe" as the entity.
Choose a better mapping between vertex type or its attributes: {verticesAttrs}.
Replace the relationships mentioned in the question to one of these choices: {edges}.
Make sure the entities are either the source vertices or target vertices of the relationships: {edgesInfo}.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
Use the vertex types, edge types, and their attributes and IDs below to write the pyTigerGraph function call to answer the question using a pyTigerGraph connection.
When the question asks for "How many", make sure to select a function that contains "Count" in the description/function call. Make sure never to generate a function that is not listed below.
When certain entities are mapped to vertex attributes, may consider to generate a WHERE clause.
If a WHERE clause is generated, please follow the instruction with proper quoting. To construct a WHERE clause string. Ensure that string attribute values are properly quoted.
For example, if the generated function is "conn.getVertices('Person', where='name=William Torres')", Expected Output: "conn.getVertices('Person', where='name="William Torres"')", This rule applies to all types of attributes. e.g., name, email, address and so on.
Documentation contains helpful Python docstrings for the various functions. Use this knowledge to construct the proper function call. Choose one function to execute.
Don't generate target_vertex_ids if there is no the term 'id' explicitly mentioned in the question.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
You are mapping a question from a user to entities represented in a graph database.
The question is: {question}
Replace the entites mentioned in the question to one of these choices: {vertices}.
Replace the entites mentioned in the question to one of these choices: {vertices}.
If an entity, such as "John Doe", is mentioned multiple times in the conversation but is referred to by different names or pronouns (e.g., "Joe", "he"),
always use the most complete identifier for that entity throughout the question. In this example, use "John Doe" as the entity.
Choose a better mapping between vertex type or its attributes: {verticesAttrs}.
Replace the relationships mentioned in the question to one of these choices: {edges}.
Make sure the entities are either the source vertices or target vertices of the relationships: {edgesInfo}.
Expand Down
2 changes: 2 additions & 0 deletions common/prompts/gcp_vertexai_palm/generate_function.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
Use the vertex types, edge types, and their attributes and IDs below to write the pyTigerGraph function call to answer the question using a pyTigerGraph connection.
When the question asks for "How many", make sure to select a function that contains "Count" in the description/function call. Make sure never to generate a function that is not listed below.
When certain entities are mapped to vertex attributes, may consider to generate a WHERE clause.
If a WHERE clause is generated, please follow the instruction with proper quoting. To construct a WHERE clause string. Ensure that string attribute values are properly quoted.
For example, if the generated function is "conn.getVertices('Person', where='name=William Torres')", Expected Output: "conn.getVertices('Person', where='name="William Torres"')", This rule applies to all types of attributes. e.g., name, email, address and so on.
Documentation contains helpful Python docstrings for the various functions. Use this knowledge to construct the proper function call. Choose one function to execute.
Don't generate target_vertex_ids if there is no the term 'id' explicitly mentioned in the question.

Expand Down
5 changes: 4 additions & 1 deletion common/prompts/gcp_vertexai_palm/map_question_to_schema.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
Replace the entites mentioned in the question to one of these choices: {vertices}.
Replace the entites mentioned in the question to one of these choices: {vertices}.
If an entity, such as "John Doe", is mentioned multiple times in the conversation but is referred to by different names or pronouns (e.g., "Joe", "he"),
always use the most complete identifier for that entity throughout the question. In this example, use "John Doe" as the entity.
Choose a better mapping between vertex type or its attributes: {verticesAttrs}.
Replace the relationships mentioned in the question to one of these choices: {edges}.
Make sure the entities are either the source vertices or target vertices of the relationships: {edgesInfo}.
When certain entities are mapped to vertex attributes, may consider to generate a WHERE clause.
If there are words that are synonyms with the entities or relationships above, make sure to output the cannonical form found in the choices above.
Generate the complete question with the appropriate replacements. Keep the case of the schema elements the same.
Don't generate target_vertex_ids if there is no the term 'id' explicitly mentioned in the question.

{format_instructions}
QUESTION: {question}
2 changes: 2 additions & 0 deletions common/prompts/llama_70b/generate_function.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
Use the vertex types, edge types, and their attributes and IDs below to write the pyTigerGraph function call to answer the question using a pyTigerGraph connection.
When the question asks for "How many", make sure to select a function that contains "Count" in the description/function call. Make sure never to generate a function that is not listed below.
When certain entities are mapped to vertex attributes, may consider to generate a WHERE clause.
If a WHERE clause is generated, please follow the instruction with proper quoting. To construct a WHERE clause string. Ensure that string attribute values are properly quoted.
For example, if the generated function is "conn.getVertices('Person', where='name=William Torres')", Expected Output: "conn.getVertices('Person', where='name="William Torres"')", This rule applies to all types of attributes. e.g., name, email, address and so on.
Documentation contains helpful Python docstrings for the various functions. Use this knowledge to construct the proper function call. Choose one function to execute.
Don't generate target_vertex_ids if there is no the term 'id' explicitly mentioned in the question.
Vertex Types: {vertex_types}
Expand Down
4 changes: 3 additions & 1 deletion common/prompts/llama_70b/map_question_to_schema.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
Replace the entites mentioned in the question to one of these choices: {vertices}.
Replace the entites mentioned in the question to one of these choices: {vertices}.
If an entity, such as "John Doe", is mentioned multiple times in the conversation but is referred to by different names or pronouns (e.g., "Joe", "he"),
always use the most complete identifier for that entity throughout the question. In this example, use "John Doe" as the entity.
Choose a better mapping between vertex type or its attributes: {verticesAttrs}.
Replace the relationships mentioned in the question to one of these choices: {edges}.
Make sure the entities are either the source vertices or target vertices of the relationships: {edgesInfo}.
Expand Down
2 changes: 2 additions & 0 deletions common/prompts/openai_gpt4/generate_function.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
Use the vertex types, edge types, and their attributes and IDs below to write the pyTigerGraph function call to answer the question using a pyTigerGraph connection.
When the question asks for "How many", make sure to select a function that contains "Count" in the description/function call. Make sure never to generate a function that is not listed below.
When certain entities are mapped to vertex attributes, may consider to generate a WHERE clause.
If a WHERE clause is generated, please follow the instruction with proper quoting. To construct a WHERE clause string. Ensure that string attribute values are properly quoted.
For example, if the generated function is "conn.getVertices('Person', where='name=William Torres')", Expected Output: "conn.getVertices('Person', where='name="William Torres"')", This rule applies to all types of attributes. e.g., name, email, address and so on.
Documentation contains helpful Python docstrings for the various functions. Use this knowledge to construct the proper function call. Choose one function to execute.
Don't generate target_vertex_ids if there is no the term 'id' explicitly mentioned in the question.
Vertex Types: {vertex_types}
Expand Down
6 changes: 5 additions & 1 deletion common/prompts/openai_gpt4/map_question_to_schema.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
Replace the entites mentioned in the question to one of these choices: {vertices}.
Replace the entites mentioned in the question to one of these choices: {vertices}.
If an entity, such as "John Doe", is mentioned multiple times in the conversation but is referred to by different names or pronouns (e.g., "Joe", "he"),
always use the most complete identifier for that entity throughout the question. In this example, use "John Doe" as the entity.
Choose a better mapping between vertex type or its attributes: {verticesAttrs}.
Replace the relationships mentioned in the question to one of these choices: {edges}.
Make sure the entities are either the source vertices or target vertices of the relationships: {edgesInfo}.
When certain entities are mapped to vertex attributes, may consider to generate a WHERE clause.
If there are words that are synonyms with the entities or relationships above, make sure to output the cannonical form found in the choices above.
Generate the complete question with the appropriate replacements. Keep the case of the schema elements the same.
Don't generate target_vertex_ids if there is no the term 'id' explicitly mentioned in the question.

{format_instructions}
QUESTION: {question}

Loading

0 comments on commit 7858a2e

Please sign in to comment.