Skip to content

Commit 4148b76

Browse files
Merge branch 'DEV' of https://github.com/neo4j-labs/llm-graph-builder into add-show-graph
2 parents 97b248c + 99c3112 commit 4148b76

File tree

16 files changed

+588
-197
lines changed

16 files changed

+588
-197
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ KNN_MIN_SCORE = ""\
114114
https://github.com/neo4j-labs/llm-graph-builder/assets/121786590/b725a503-6ade-46d2-9e70-61d57443c311
115115
116116
## Links
117-
The Public [ Google cloud Run URL](https://devfrontend-dcavk67s4a-uc.a.run.app/).
117+
The Public [ Google cloud Run URL](https://staging-frontend-dcavk67s4a-uc.a.run.app/).
118118
[Workspace URL](https://workspace-preview.neo4j.io/workspace)
119119
120120

backend/score.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,16 +57,17 @@ async def create_source_knowledge_graph_url(
5757
uri=Form(None),
5858
userName=Form(None),
5959
password=Form(None),
60-
source_url=Form(),
60+
source_url=Form(None),
6161
database=Form(None),
6262
aws_access_key_id=Form(None),
6363
aws_secret_access_key=Form(None),
6464
max_limit=Form(5),
6565
query_source=Form(None),
66+
wiki_query=Form(None),
6667
model=Form(None)
6768
):
6869
return create_source_node_graph_url(
69-
uri, userName, password, source_url, model, database, aws_access_key_id, aws_secret_access_key
70+
uri, userName, password, model, source_url, database, wiki_query, aws_access_key_id, aws_secret_access_key
7071
)
7172

7273

@@ -126,6 +127,17 @@ async def extract_knowledge_graph_from_file(
126127
wiki_query=wiki_query,
127128
max_sources=max_sources,
128129
)
130+
elif wiki_query:
131+
return await asyncio.to_thread(
132+
extract_graph_from_file,
133+
uri,
134+
userName,
135+
password,
136+
model,
137+
database,
138+
wiki_query=wiki_query
139+
)
140+
129141
else:
130142
return {"job_status": "Failure", "error": "No file found"}
131143

@@ -161,8 +173,8 @@ async def chat_bot(uri=Form(None),
161173
userName=Form(None),
162174
password=Form(None),
163175
question=Form(None),
164-
model=Form(None)):
165-
result = await asyncio.to_thread(QA_RAG,uri=uri,userName=userName,password=password,model_version=model,question=question)
176+
session_id=Form(None)):
177+
result = await asyncio.to_thread(QA_RAG,uri=uri,userName=userName,password=password,question=question,session_id=session_id)
166178
return result
167179

168180
@app.post("/connect")

backend/src/QA_integration.py

Lines changed: 71 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,58 +7,95 @@
77
from langchain_openai import ChatOpenAI
88
from langchain_openai import OpenAIEmbeddings
99
import logging
10+
from langchain_community.chat_message_histories import Neo4jChatMessageHistory
11+
import asyncio
1012
load_dotenv()
1113

1214
openai_api_key = os.environ.get('OPENAI_API_KEY')
15+
model_version='gpt-4-0125-preview'
1316

1417
def vector_embed_results(qa,question):
1518
vector_res={}
1619
try:
17-
# question ="What do you know about machine learning"
1820
result = qa({"query": question})
19-
vector_res['result']=result["result"]
21+
vector_res['result']=result.get("result")
2022
list_source_docs=[]
2123
for i in result["source_documents"]:
2224
list_source_docs.append(i.metadata['source'])
2325
vector_res['source']=list_source_docs
2426
except Exception as e:
2527
error_message = str(e)
2628
logging.exception(f'Exception in vector embedding in QA component:{error_message}')
27-
raise Exception(error_message)
29+
# raise Exception(error_message)
2830

2931
return vector_res
3032

31-
def cypher_results(graph,question,model_version):
33+
def cypher_results(graph,question):
3234
cypher_res={}
3335
try:
3436
graph.refresh_schema()
3537
cypher_chain = GraphCypherQAChain.from_llm(
3638
graph=graph,
37-
# cypher_llm=ChatOpenAI(temperature=0, model="gpt-4"),
3839
cypher_llm=ChatOpenAI(temperature=0, model=model_version),
3940
qa_llm=ChatOpenAI(temperature=0, model=model_version),
4041
validate_cypher=True, # Validate relationship directions
4142
verbose=True,
4243
top_k=2
4344
)
44-
45-
cypher_res=cypher_chain.invoke({"query": question})
45+
try:
46+
cypher_res=cypher_chain.invoke({"query": question})
47+
except:
48+
cypher_res={}
4649

4750
except Exception as e:
4851
error_message = str(e)
4952
logging.exception(f'Exception in CypherQAChain in QA component:{error_message}')
50-
raise Exception(error_message)
53+
# raise Exception(error_message)
5154

5255
return cypher_res
5356

57+
def save_chat_history(uri,userName,password,session_id,user_message,ai_message):
58+
try:
59+
history = Neo4jChatMessageHistory(
60+
url=uri,
61+
username=userName,
62+
password=password,
63+
session_id=session_id
64+
)
65+
history.add_user_message(user_message)
66+
history.add_ai_message(ai_message)
67+
logging.info(f'Successfully saved chat history')
68+
except Exception as e:
69+
error_message = str(e)
70+
logging.exception(f'Exception in saving chat history:{error_message}')
71+
# raise Exception(error_message)
72+
5473

74+
def get_chat_history(llm,uri,userName,password,session_id):
75+
try:
76+
history = Neo4jChatMessageHistory(
77+
url=uri,
78+
username=userName,
79+
password=password,
80+
session_id=session_id
81+
)
82+
chat_history=history.messages
5583

56-
def QA_RAG(uri,userName,password,model_version,question):
84+
if len(chat_history)==0:
85+
return ""
86+
condense_template = f"""Given the following earlier conversation , Summarise the chat history.Make sure to include all the relevant information.
87+
Chat History:
88+
{chat_history}"""
89+
chat_summary=llm.predict(condense_template)
90+
return chat_summary
91+
except Exception as e:
92+
error_message = str(e)
93+
logging.exception(f'Exception in retrieving chat history:{error_message}')
94+
# raise Exception(error_message)
95+
return ''
96+
97+
def QA_RAG(uri,userName,password,question,session_id):
5798
try:
58-
if model_version=='OpenAI GPT 3.5':
59-
model_version='gpt-3.5-turbo'
60-
elif model_version=='OpenAI GPT 4':
61-
model_version='gpt-4-0125-preview'
6299
retrieval_query="""
63100
MATCH (node)-[:PART_OF]->(d:Document)
64101
WITH d, apoc.text.join(collect(node.text),"\n----\n") as text, avg(score) as score
@@ -77,7 +114,7 @@ def QA_RAG(uri,userName,password,model_version,question):
77114
llm = ChatOpenAI(model= model_version, temperature=0)
78115

79116
qa = RetrievalQA.from_chain_type(
80-
llm=llm, chain_type="stuff", retriever=neo_db.as_retriever(search_kwargs={"score_threshold": 0.5}), return_source_documents=True
117+
llm=llm, chain_type="stuff", retriever=neo_db.as_retriever(search_kwargs={'k': 3,"score_threshold": 0.5}), return_source_documents=True
81118
)
82119

83120
graph = Neo4jGraph(
@@ -86,24 +123,39 @@ def QA_RAG(uri,userName,password,model_version,question):
86123
password=password
87124
)
88125
vector_res=vector_embed_results(qa,question)
126+
print('Response from Vector embeddings')
89127
print(vector_res)
90-
cypher_res= cypher_results(graph,question,model_version)
128+
cypher_res= cypher_results(graph,question)
129+
print('Response from CypherQAChain')
91130
print(cypher_res)
131+
132+
chat_summary=get_chat_history(llm,uri,userName,password,session_id)
133+
92134
final_prompt = f"""You are a helpful question-answering agent. Your task is to analyze
93135
and synthesize information from two sources: the top result from a similarity search
94-
(unstructured information) and relevant data from a graph database (structured information).
136+
(unstructured information) and relevant data from a graph database (structured information).
137+
If structured information fails to find an answer then use the answer from unstructured information
138+
and vice versa. I only want a straightforward answer without mentioning from which source you got the answer. You are also receiving
139+
a chat history of the earlier conversation. You should be able to understand the context from the chat history and answer the question.
95140
Given the user's query: {question}, provide a meaningful and efficient answer based
96141
on the insights derived from the following data:
142+
chat_summary:{chat_summary}
97143
Structured information: {cypher_res.get('result','')}.
98144
Unstructured information: {vector_res.get('result','')}.
99145
100-
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.
101146
"""
102147
print(final_prompt)
103148
response = llm.predict(final_prompt)
104-
res={"message":response,"user":"chatbot"}
149+
ai_message=response
150+
user_message=question
151+
save_chat_history(uri,userName,password,session_id,user_message,ai_message)
152+
153+
res={"session_id":session_id,"message":response,"user":"chatbot"}
105154
return res
106155
except Exception as e:
107156
error_message = str(e)
108157
logging.exception(f'Exception in in QA component:{error_message}')
109-
raise Exception(error_message)
158+
# raise Exception(error_message)
159+
return {"session_id":session_id,"message":"Something went wrong","user":"chatbot"}
160+
161+

0 commit comments

Comments
 (0)