Update app.py
Browse files
app.py
CHANGED
@@ -95,7 +95,7 @@ def transform_query(query: str) -> str:
|
|
95 |
"""
|
96 |
return f'Represent this sentence for searching relevant passages: {query}'
|
97 |
|
98 |
-
def query_hybrid_search(query: str, client: QdrantClient, collection_name: str,
|
99 |
return client.query_points(
|
100 |
collection_name=collection_name,
|
101 |
prefetch=[
|
@@ -121,7 +121,7 @@ def build_prompt_conv():
|
|
121 |
},
|
122 |
{
|
123 |
'role': 'user',
|
124 |
-
'content': f"""Generate a short, single-sentence summary of the user's intent or topic based on their question, capturing the main focus of what they want to discuss. Do NOT cite the user.
|
125 |
|
126 |
Question : {st.session_state.user_input}
|
127 |
"""
|
@@ -228,59 +228,74 @@ def self_knowledge(query: str):
|
|
228 |
Question: {{ query }}
|
229 |
"""
|
230 |
|
231 |
-
def
|
232 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
233 |
sparse_embeddings = list(sparse_model.query_embed(query))[0].as_object()
|
234 |
|
235 |
s = time.time()
|
236 |
-
scored_points = query_hybrid_search(query, client, collection_name, dense_embeddings, sparse_embeddings).points
|
237 |
-
print(f'Score : {scored_points[0]}')
|
238 |
-
docs = [(scored_point.payload['text'], scored_point.payload['metadata']) for scored_point in scored_points]
|
239 |
-
contents, metadatas = [list(t) for t in zip(*docs)]
|
240 |
-
|
241 |
-
context = "\n".join(contents)
|
242 |
-
print(f'Context : \n + {context}')
|
243 |
|
244 |
-
|
245 |
-
|
246 |
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
if action == 'Yes':
|
253 |
-
filtered_metadatas = {
|
254 |
-
value
|
255 |
-
for metadata in metadatas
|
256 |
-
if 'url' in metadata
|
257 |
-
for value in [metadata['url']]
|
258 |
-
}
|
259 |
-
result_metadatas = "\n\n".join(f'{value}' for value in filtered_metadatas)
|
260 |
|
261 |
-
|
262 |
-
|
263 |
-
|
|
|
|
|
|
|
|
|
264 |
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
275 |
else:
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
|
|
282 |
answer = json.loads(gen_text(prompt, max_tokens=300, sampling_params=SamplingParams(temperature=0.6, top_p=0.9, top_k=10)))['answer']
|
283 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
284 |
|
285 |
torch.cuda.empty_cache()
|
286 |
|
@@ -577,28 +592,11 @@ def load_models_and_documents():
|
|
577 |
container.empty()
|
578 |
|
579 |
return client, collection_name, llm, model, dense_model, sparse_model, nlp, conn, cursor
|
580 |
-
|
581 |
-
def on_change_documents_only():
|
582 |
-
if st.session_state.documents_only:
|
583 |
-
st.session_state.initialized = True
|
584 |
-
st.session_state.toggle_docs = {
|
585 |
-
'tooltip': 'The AI answer your questions only considering the documents provided',
|
586 |
-
'display': True
|
587 |
-
}
|
588 |
-
else:
|
589 |
-
st.session_state.initialized = False
|
590 |
-
st.session_state.toggle_docs = {
|
591 |
-
'tooltip': """The AI answer your questions considering the documents provided, and if it doesn't found the answer in them, try to find in its own internal knowledge""",
|
592 |
-
'display': False
|
593 |
-
}
|
594 |
|
595 |
|
596 |
if __name__ == '__main__':
|
597 |
st.set_page_config(page_title="Multipurpose AI Agent",layout="wide", initial_sidebar_state='auto')
|
598 |
|
599 |
-
if 'initialized' not in st.session_state:
|
600 |
-
st.session_state.initialized = True
|
601 |
-
|
602 |
client, collection_name, llm, model, dense_model, sparse_model, nlp, conn, cursor = load_models_and_documents()
|
603 |
|
604 |
styles = {
|
@@ -752,6 +750,10 @@ if __name__ == '__main__':
|
|
752 |
if 'id_chat' not in st.session_state:
|
753 |
st.session_state.id_chat = 'New Conversation'
|
754 |
|
|
|
|
|
|
|
|
|
755 |
def options_list(conversations: Dict[str, list]):
|
756 |
if st.session_state.id_chat == 'New Conversation':
|
757 |
return [st.session_state.id_chat] + list(conversations.keys())
|
@@ -760,10 +762,9 @@ if __name__ == '__main__':
|
|
760 |
|
761 |
with st.sidebar:
|
762 |
st.session_state.id_chat = st.selectbox(
|
763 |
-
label='Choose a
|
764 |
options=options_list(conversations),
|
765 |
index=0,
|
766 |
-
placeholder='_',
|
767 |
key='chat_id'
|
768 |
)
|
769 |
|
@@ -775,7 +776,6 @@ if __name__ == '__main__':
|
|
775 |
packed_bytes = msgpack.packb(conversations, use_bin_type=True)
|
776 |
fp.write(packed_bytes)
|
777 |
st.session_state.chat_id = 'New Conversation'
|
778 |
-
|
779 |
|
780 |
st.button(
|
781 |
'Delete Conversation',
|
@@ -785,6 +785,25 @@ if __name__ == '__main__':
|
|
785 |
args=(conversations_path, conversations)
|
786 |
)
|
787 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
788 |
def generate_conv_title(llm):
|
789 |
if st.session_state.chat_id == 'New Conversation':
|
790 |
output = llm.chat(
|
@@ -815,7 +834,7 @@ if __name__ == '__main__':
|
|
815 |
st.chat_message("user").markdown(prompt)
|
816 |
st.session_state.messages.append({"role": "user", "content": prompt})
|
817 |
|
818 |
-
ai_response =
|
819 |
with st.chat_message("assistant"):
|
820 |
message_placeholder = st.empty()
|
821 |
full_response = ""
|
@@ -843,7 +862,7 @@ if __name__ == '__main__':
|
|
843 |
'tooltip': 'The AI answer your questions only considering the documents provided',
|
844 |
'display': True
|
845 |
}
|
846 |
-
|
847 |
st.toggle(
|
848 |
label="""Enable 'Documents-Only' Mode""",
|
849 |
value=st.session_state.toggle_docs['display'],
|
|
|
95 |
"""
|
96 |
return f'Represent this sentence for searching relevant passages: {query}'
|
97 |
|
98 |
+
def query_hybrid_search(query: str, client: QdrantClient, collection_name: str, dense_embeddings, sparse_embeddings):
|
99 |
return client.query_points(
|
100 |
collection_name=collection_name,
|
101 |
prefetch=[
|
|
|
121 |
},
|
122 |
{
|
123 |
'role': 'user',
|
124 |
+
'content': f"""Generate a short, single-sentence summary, in 10 tokens maximum, of the user's intent or topic based on their question, capturing the main focus of what they want to discuss. Do NOT cite the user.
|
125 |
|
126 |
Question : {st.session_state.user_input}
|
127 |
"""
|
|
|
228 |
Question: {{ query }}
|
229 |
"""
|
230 |
|
231 |
+
def generate_answer(query: str,
|
232 |
+
client: QdrantClient,
|
233 |
+
collection_name: str,
|
234 |
+
llm,
|
235 |
+
dense_model: AsyncEmbeddingEngine,
|
236 |
+
sparse_model: SparseTextEmbedding,
|
237 |
+
past_messages: str,
|
238 |
+
search_strategy: str,
|
239 |
+
):
|
240 |
sparse_embeddings = list(sparse_model.query_embed(query))[0].as_object()
|
241 |
|
242 |
s = time.time()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
243 |
|
244 |
+
if search_strategy == 'Exact Search':
|
245 |
+
scored_points = query_keywords_search(query, client, collection_name, sparse_embeddings).points
|
246 |
|
247 |
+
answer = f"{scored_points[0].payload['text']}\n\n\nSource :\n\n{scored_points[0].payload['metadata']}"
|
248 |
+
else:
|
249 |
+
regex = build_regex_from_schema(schema, r"[\n ]?")
|
250 |
+
gen_text = outlines.generate.regex(llm, regex)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
251 |
|
252 |
+
gen_choice = outlines.generate.choice(llm, choices=['Yes', 'No'])
|
253 |
+
prompt = route_llm(context, query)
|
254 |
+
action = gen_choice(prompt, max_tokens=2, sampling_params=SamplingParams(temperature=0))
|
255 |
+
print(f'Choice: {action}')
|
256 |
+
|
257 |
+
if action == 'Yes':
|
258 |
+
dense_embeddings, tokens_count = asyncio.run(embed_text(dense_model[0], transform_query(query)))
|
259 |
|
260 |
+
scored_points = query_hybrid_search(query, client, collection_name, dense_embeddings, sparse_embeddings).points
|
261 |
+
print(f'Score : {scored_points[0]}')
|
262 |
+
docs = [(scored_point.payload['text'], scored_point.payload['metadata']) for scored_point in scored_points]
|
263 |
+
contents, metadatas = [list(t) for t in zip(*docs)]
|
264 |
+
|
265 |
+
context = "\n".join(contents)
|
266 |
+
print(f'Context : \n + {context}')
|
267 |
+
|
268 |
+
filtered_metadatas = {
|
269 |
+
value
|
270 |
+
for metadata in metadatas
|
271 |
+
if 'url' in metadata
|
272 |
+
for value in [metadata['url']]
|
273 |
+
}
|
274 |
+
result_metadatas = "\n\n".join(f'{value}' for value in filtered_metadatas)
|
275 |
+
|
276 |
+
prompt = answer_with_context(context, query)
|
277 |
+
answer = json.loads(gen_text(prompt, max_tokens=300, sampling_params=SamplingParams(temperature=0)))['answer']
|
278 |
+
answer = f"{answer}\n\n\nSource(s) :\n\n{result_metadatas}"
|
279 |
+
|
280 |
+
if search_strategy == 'Documents + LLM Search':
|
281 |
+
answer = f'Documents Based :\n\n{answer}'
|
282 |
else:
|
283 |
+
gen_choice = outlines.generate.choice(llm, choices=['Domain-Specific Question', 'General Question'])
|
284 |
+
prompt = question_type_prompt(query)
|
285 |
+
action = gen_choice(prompt, max_tokens=3, sampling_params=SamplingParams(temperature=0))
|
286 |
+
print(f'Choice 2: {action}')
|
287 |
+
|
288 |
+
if action == 'General Question':
|
289 |
+
prompt = open_query_prompt(past_messages, query)
|
290 |
answer = json.loads(gen_text(prompt, max_tokens=300, sampling_params=SamplingParams(temperature=0.6, top_p=0.9, top_k=10)))['answer']
|
291 |
+
else:
|
292 |
+
if search_strategy == 'Documents Only Search':
|
293 |
+
prompt = idk(query)
|
294 |
+
answer = json.loads(gen_text(prompt, max_tokens=128, sampling_params=SamplingParams(temperature=0.6, top_p=0.9, top_k=10)))['answer']
|
295 |
+
elif search_strategy == 'Documents + LLM Search':
|
296 |
+
prompt = self_knowledge(query)
|
297 |
+
answer = json.loads(gen_text(prompt, max_tokens=300, sampling_params=SamplingParams(temperature=0.6, top_p=0.9, top_k=10)))['answer']
|
298 |
+
answer = f'Internal Knowledge :\n\n{answer}'
|
299 |
|
300 |
torch.cuda.empty_cache()
|
301 |
|
|
|
592 |
container.empty()
|
593 |
|
594 |
return client, collection_name, llm, model, dense_model, sparse_model, nlp, conn, cursor
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
595 |
|
596 |
|
597 |
if __name__ == '__main__':
|
598 |
st.set_page_config(page_title="Multipurpose AI Agent",layout="wide", initial_sidebar_state='auto')
|
599 |
|
|
|
|
|
|
|
600 |
client, collection_name, llm, model, dense_model, sparse_model, nlp, conn, cursor = load_models_and_documents()
|
601 |
|
602 |
styles = {
|
|
|
750 |
if 'id_chat' not in st.session_state:
|
751 |
st.session_state.id_chat = 'New Conversation'
|
752 |
|
753 |
+
if 'search_strategy' not in st.session_state:
|
754 |
+
st.session_state.search_strategy = 'Documents Only Search'
|
755 |
+
st.session_state.tooltip = 'The AI answer your questions only considering the documents provided'
|
756 |
+
|
757 |
def options_list(conversations: Dict[str, list]):
|
758 |
if st.session_state.id_chat == 'New Conversation':
|
759 |
return [st.session_state.id_chat] + list(conversations.keys())
|
|
|
762 |
|
763 |
with st.sidebar:
|
764 |
st.session_state.id_chat = st.selectbox(
|
765 |
+
label='Choose a Conversation',
|
766 |
options=options_list(conversations),
|
767 |
index=0,
|
|
|
768 |
key='chat_id'
|
769 |
)
|
770 |
|
|
|
776 |
packed_bytes = msgpack.packb(conversations, use_bin_type=True)
|
777 |
fp.write(packed_bytes)
|
778 |
st.session_state.chat_id = 'New Conversation'
|
|
|
779 |
|
780 |
st.button(
|
781 |
'Delete Conversation',
|
|
|
785 |
args=(conversations_path, conversations)
|
786 |
)
|
787 |
|
788 |
+
st.divider()
|
789 |
+
|
790 |
+
def tooltip_change():
|
791 |
+
if st.session_state.search_id == 'Exact Search':
|
792 |
+
st.session_state.tooltip = 'Search the exact definition'
|
793 |
+
elif st.session_state.search_id == 'Documents Only Search':
|
794 |
+
st.session_state.tooltip = 'The AI answer your questions only considering the documents provided'
|
795 |
+
elif st.session_state.search_id == 'Documents + LLM Search':
|
796 |
+
st.session_state.tooltip = 'The AI answer your questions considering the documents provided, and if it doesn't found the answer in them, try to find in its own internal knowledge'
|
797 |
+
|
798 |
+
st.session_state.search_strategy = st.radio(
|
799 |
+
label='Choose a Search Strategy',
|
800 |
+
options=['Exact Search', 'Documents Only Search', 'Documents + LLM Search'],
|
801 |
+
index=1,
|
802 |
+
on_change=tooltip_change,
|
803 |
+
key='search_id',
|
804 |
+
help=st.session_state.tooltip
|
805 |
+
)
|
806 |
+
|
807 |
def generate_conv_title(llm):
|
808 |
if st.session_state.chat_id == 'New Conversation':
|
809 |
output = llm.chat(
|
|
|
834 |
st.chat_message("user").markdown(prompt)
|
835 |
st.session_state.messages.append({"role": "user", "content": prompt})
|
836 |
|
837 |
+
ai_response = generate_answer(prompt, client, collection_name, model, dense_model, sparse_model, "\n".join([f'{msg["role"]}: {msg["content"]}' for msg in st.session_state.messages]), st.session_state.search_strategy)
|
838 |
with st.chat_message("assistant"):
|
839 |
message_placeholder = st.empty()
|
840 |
full_response = ""
|
|
|
862 |
'tooltip': 'The AI answer your questions only considering the documents provided',
|
863 |
'display': True
|
864 |
}
|
865 |
+
|
866 |
st.toggle(
|
867 |
label="""Enable 'Documents-Only' Mode""",
|
868 |
value=st.session_state.toggle_docs['display'],
|