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 |
|