Skip to content

Commit efd865b

Browse files
Q/A component added
1 parent 854faf1 commit efd865b

File tree

1 file changed

+87
-0
lines changed

1 file changed

+87
-0
lines changed

backend/src/QA_integration.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
from langchain_community.vectorstores.neo4j_vector import Neo4jVector
2+
from langchain.chains import GraphCypherQAChain
3+
from langchain.graphs import Neo4jGraph
4+
import os
5+
from dotenv import load_dotenv
6+
from langchain.chains import RetrievalQA
7+
from langchain_openai import ChatOpenAI
8+
from langchain_openai import OpenAIEmbeddings
9+
load_dotenv()
10+
11+
openai_api_key = os.environ.get('OPENAI_API_KEY')
12+
13+
def vector_embed_results(qa,question):
14+
# question ="What do you know about machine learning"
15+
result = qa({"query": question})
16+
vector_res={}
17+
vector_res['result']=result["result"]
18+
list_source_docs=[]
19+
for i in result["source_documents"]:
20+
list_source_docs.append(i.metadata['source'])
21+
vector_res['source']=list_source_docs
22+
return vector_res
23+
24+
def cypher_results(graph,question,model_version):
25+
graph.refresh_schema()
26+
cypher_chain = GraphCypherQAChain.from_llm(
27+
graph=graph,
28+
# cypher_llm=ChatOpenAI(temperature=0, model="gpt-4"),
29+
cypher_llm=ChatOpenAI(temperature=0, model=model_version),
30+
qa_llm=ChatOpenAI(temperature=0, model=model_version),
31+
validate_cypher=True, # Validate relationship directions
32+
verbose=True,
33+
top_k=2
34+
)
35+
36+
cypher_res=cypher_chain.invoke({"query": question})
37+
return cypher_res
38+
39+
40+
def QA_RAG(uri,userName,password,model_version,question):
41+
if model_version=='OpenAI GPT 3.5':
42+
model_version='gpt-3.5-turbo'
43+
elif model_version=='OpenAI GPT 4':
44+
model_version='gpt-4-0125-preview'
45+
retrieval_query="""
46+
MATCH (node)-[:PART_OF]->(d:Document)
47+
WITH d, apoc.text.join(collect(node.text),"\n----\n") as text, avg(score) as score
48+
RETURN text, score, {source: COALESCE(CASE WHEN d.url CONTAINS "None" THEN d.fileName ELSE d.url END, d.fileName)} as metadata
49+
"""
50+
51+
neo_db=Neo4jVector.from_existing_index(
52+
embedding=OpenAIEmbeddings(),
53+
url=uri,
54+
username=userName,
55+
password=password,
56+
database="neo4j",
57+
index_name="vector",
58+
retrieval_query=retrieval_query,
59+
)
60+
llm = ChatOpenAI(model= model_version, temperature=0)
61+
62+
qa = RetrievalQA.from_chain_type(
63+
llm=llm, chain_type="stuff", retriever=neo_db.as_retriever(search_kwargs={"score_threshold": 0.5}), return_source_documents=True
64+
)
65+
66+
graph = Neo4jGraph(
67+
url=uri,
68+
username=userName,
69+
password=password
70+
)
71+
vector_res=vector_embed_results(qa,question)
72+
print(vector_res)
73+
cypher_res= cypher_results(graph,question,model_version)
74+
print(cypher_res)
75+
final_prompt = f"""You are a helpful question-answering agent. Your task is to analyze
76+
and synthesize information from two sources: the top result from a similarity search
77+
(unstructured information) and relevant data from a graph database (structured information).
78+
Given the user's query: {question}, provide a meaningful and efficient answer based
79+
on the insights derived from the following data:
80+
Structured information: {cypher_res['result']}.
81+
Unstructured information: {vector_res['result']}.
82+
83+
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.
84+
"""
85+
response = llm.predict(final_prompt)
86+
res={"message":response,"user":"chatbot"}
87+
return res

0 commit comments

Comments
 (0)