Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
@@ -17,7 +17,20 @@ graph = Neo4jGraph(
|
|
17 |
password="Z10duoPkKCtENuOukw3eIlvl0xJWKtrVSr-_hGX1LQ4"
|
18 |
)
|
19 |
|
20 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
def remove_lucene_chars(input: str) -> str:
|
22 |
return input.translate(str.maketrans({
|
23 |
"\\": r"\\", "+": r"\+", "-": r"\-", "&": r"\&", "|": r"\|", "!": r"\!",
|
@@ -26,7 +39,6 @@ def remove_lucene_chars(input: str) -> str:
|
|
26 |
";": r"\;", " ": r"\ "
|
27 |
}))
|
28 |
|
29 |
-
# Function to generate a full-text query
|
30 |
def generate_full_text_query(input: str) -> str:
|
31 |
full_text_query = ""
|
32 |
words = [el for el in remove_lucene_chars(input).split() if el]
|
@@ -35,29 +47,100 @@ def generate_full_text_query(input: str) -> str:
|
|
35 |
full_text_query += f" {words[-1]}~2"
|
36 |
return full_text_query.strip()
|
37 |
|
38 |
-
#
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
|
|
|
|
43 |
response = graph.query(
|
44 |
-
"""
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
""",
|
50 |
-
{"query":
|
51 |
)
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
58 |
except Exception as e:
|
59 |
-
|
60 |
-
|
|
|
61 |
|
62 |
# Function to generate audio with Eleven Labs TTS
|
63 |
def generate_audio_elevenlabs(text):
|
@@ -131,8 +214,8 @@ def handle_voice_to_voice(audio):
|
|
131 |
|
132 |
|
133 |
# Define the Gradio interface
|
134 |
-
with gr.Blocks() as demo:
|
135 |
-
audio_input = gr.Audio(sources=["microphone"], type='numpy', streaming=
|
136 |
submit_voice_btn = gr.Button("Submit Voice")
|
137 |
audio_output = gr.Audio(label="Response Audio", type="filepath", autoplay=True, interactive=False)
|
138 |
|
|
|
17 |
password="Z10duoPkKCtENuOukw3eIlvl0xJWKtrVSr-_hGX1LQ4"
|
18 |
)
|
19 |
|
20 |
+
# Define entity extraction and retrieval functions
|
21 |
+
class Entities(BaseModel):
|
22 |
+
names: List[str] = Field(
|
23 |
+
..., description="All the person, organization, or business entities that appear in the text"
|
24 |
+
)
|
25 |
+
|
26 |
+
entity_prompt = ChatPromptTemplate.from_messages([
|
27 |
+
("system", "You are extracting organization and person entities from the text."),
|
28 |
+
("human", "Use the given format to extract information from the following input: {question}"),
|
29 |
+
])
|
30 |
+
|
31 |
+
chat_model = ChatOpenAI(temperature=0, model_name="gpt-4o", api_key=os.environ['OPENAI_API_KEY'])
|
32 |
+
entity_chain = entity_prompt | chat_model.with_structured_output(Entities)
|
33 |
+
|
34 |
def remove_lucene_chars(input: str) -> str:
|
35 |
return input.translate(str.maketrans({
|
36 |
"\\": r"\\", "+": r"\+", "-": r"\-", "&": r"\&", "|": r"\|", "!": r"\!",
|
|
|
39 |
";": r"\;", " ": r"\ "
|
40 |
}))
|
41 |
|
|
|
42 |
def generate_full_text_query(input: str) -> str:
|
43 |
full_text_query = ""
|
44 |
words = [el for el in remove_lucene_chars(input).split() if el]
|
|
|
47 |
full_text_query += f" {words[-1]}~2"
|
48 |
return full_text_query.strip()
|
49 |
|
50 |
+
# Setup logging to a file to capture debug information
|
51 |
+
logging.basicConfig(filename='neo4j_retrieval.log', level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
|
52 |
+
|
53 |
+
def structured_retriever(question: str) -> str:
|
54 |
+
result = ""
|
55 |
+
entities = entity_chain.invoke({"question": question})
|
56 |
+
for entity in entities.names:
|
57 |
response = graph.query(
|
58 |
+
"""CALL db.index.fulltext.queryNodes('entity', $query, {limit:2})
|
59 |
+
YIELD node,score
|
60 |
+
CALL {
|
61 |
+
WITH node
|
62 |
+
MATCH (node)-[r:!MENTIONS]->(neighbor)
|
63 |
+
RETURN node.id + ' - ' + type(r) + ' -> ' + neighbor.id AS output
|
64 |
+
UNION ALL
|
65 |
+
WITH node
|
66 |
+
MATCH (node)<-[r:!MENTIONS]-(neighbor)
|
67 |
+
RETURN neighbor.id + ' - ' + type(r) + ' -> ' + node.id AS output
|
68 |
+
}
|
69 |
+
RETURN output LIMIT 50
|
70 |
""",
|
71 |
+
{"query": generate_full_text_query(entity)},
|
72 |
)
|
73 |
+
result += "\n".join([el['output'] for el in response])
|
74 |
+
return result
|
75 |
+
|
76 |
+
def retriever_neo4j(question: str):
|
77 |
+
structured_data = structured_retriever(question)
|
78 |
+
logging.debug(f"Structured data: {structured_data}")
|
79 |
+
return structured_data
|
80 |
+
|
81 |
+
# Setup for condensing the follow-up questions
|
82 |
+
_template = """Given the following conversation and a follow-up question, rephrase the follow-up question to be a standalone question,
|
83 |
+
in its original language.
|
84 |
+
Chat History:
|
85 |
+
{chat_history}
|
86 |
+
Follow Up Input: {question}
|
87 |
+
Standalone question:"""
|
88 |
+
|
89 |
+
CONDENSE_QUESTION_PROMPT = PromptTemplate.from_template(_template)
|
90 |
+
|
91 |
+
def _format_chat_history(chat_history: list[tuple[str, str]]) -> list:
|
92 |
+
buffer = []
|
93 |
+
for human, ai in chat_history:
|
94 |
+
buffer.append(HumanMessage(content=human))
|
95 |
+
buffer.append(AIMessage(content=ai))
|
96 |
+
return buffer
|
97 |
+
|
98 |
+
_search_query = RunnableBranch(
|
99 |
+
(
|
100 |
+
RunnableLambda(lambda x: bool(x.get("chat_history"))).with_config(
|
101 |
+
run_name="HasChatHistoryCheck"
|
102 |
+
),
|
103 |
+
RunnablePassthrough.assign(
|
104 |
+
chat_history=lambda x: _format_chat_history(x["chat_history"])
|
105 |
+
)
|
106 |
+
| CONDENSE_QUESTION_PROMPT
|
107 |
+
| ChatOpenAI(temperature=0, api_key=os.environ['OPENAI_API_KEY'])
|
108 |
+
| StrOutputParser(),
|
109 |
+
),
|
110 |
+
RunnableLambda(lambda x: x["question"]),
|
111 |
+
)
|
112 |
+
|
113 |
+
|
114 |
+
template = """I am a guide for Birmingham, Alabama. I can provide recommendations and insights about the city, including events and activities.
|
115 |
+
Ask your question directly, and I'll provide a precise and quick,short and crisp response in a conversational way without any Greet.
|
116 |
+
{context}
|
117 |
+
Question: {question}
|
118 |
+
Answer:"""
|
119 |
+
|
120 |
+
|
121 |
+
qa_prompt = ChatPromptTemplate.from_template(template)
|
122 |
+
|
123 |
+
# Define the chain for Neo4j-based retrieval and response generation
|
124 |
+
chain_neo4j = (
|
125 |
+
RunnableParallel(
|
126 |
+
{
|
127 |
+
"context": RunnableLambda(lambda x: retriever_neo4j(x["question"])),
|
128 |
+
"question": RunnablePassthrough(),
|
129 |
+
}
|
130 |
+
)
|
131 |
+
| ChatPromptTemplate.from_template("Answer: {context} Question: {question}")
|
132 |
+
| chat_model
|
133 |
+
| StrOutputParser()
|
134 |
+
)
|
135 |
+
|
136 |
+
# Define the function to query Neo4j and get a response
|
137 |
+
def get_response(question):
|
138 |
+
try:
|
139 |
+
return chain_neo4j.invoke({"question": question})
|
140 |
except Exception as e:
|
141 |
+
return f"Error: {str(e)}"
|
142 |
+
|
143 |
+
|
144 |
|
145 |
# Function to generate audio with Eleven Labs TTS
|
146 |
def generate_audio_elevenlabs(text):
|
|
|
214 |
|
215 |
|
216 |
# Define the Gradio interface
|
217 |
+
with gr.Blocks(theme="rawrsor1/Everforest") as demo:
|
218 |
+
audio_input = gr.Audio(sources=["microphone"], type='numpy', streaming=True, label="Speak to Ask")
|
219 |
submit_voice_btn = gr.Button("Submit Voice")
|
220 |
audio_output = gr.Audio(label="Response Audio", type="filepath", autoplay=True, interactive=False)
|
221 |
|