nibas commited on
Commit
f25e2d7
·
verified ·
1 Parent(s): 207b9f8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +104 -63
app.py CHANGED
@@ -4,6 +4,8 @@ from sklearn.metrics.pairwise import cosine_similarity
4
  import re
5
  from huggingface_hub import InferenceClient
6
  import os
 
 
7
 
8
 
9
 
@@ -17,7 +19,6 @@ my_initial_rag_text = f"""This is a RAG (Retrieval-Augmented Generation) chatbot
17
  - Uses Streamlit for the web interface
18
  - Employs SentenceTransformer for generating embeddings
19
  - Uses HuggingFace's InferenceClient for LLM interaction
20
- - Has a default text about a GRNET training module on LLMs
21
 
22
  2. State Management:
23
  - Maintains several session state variables for:
@@ -83,24 +84,39 @@ if "embeddings_model" not in st.session_state:
83
  # We will use the all-MiniLM-L6-v2 model for embeddings
84
  st.session_state["embeddings_model"] = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')
85
 
86
- MAXIMUM_TOKENS = 512
87
 
88
  my_system_instructions = "You are a helpful assistant. Be brief and concise. Provide your answers in 100 words or less."
89
 
90
  first_message = "Hello, how can I help you today?"
91
 
92
- # Check if the chat messages are not already in the session state
93
- if "my_chat_messages" not in st.session_state:
94
- # Initialize the chat messages list in the session state
95
- st.session_state["my_chat_messages"] = []
96
- # Add the system instructions to the chat messages
97
- st.session_state["my_chat_messages"].append({"role": "system", "content": my_system_instructions})
98
-
99
  def delete_chat_messages():
100
  for key in st.session_state.keys():
101
- if key != "my_rag_text":
102
  del st.session_state[key]
103
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  augmented_prompt = ""
105
 
106
  # Create two columns with a 1:2 ratio
@@ -118,7 +134,7 @@ Large Language Models may provide wrong answers. Please verify the answers and c
118
  The user agrees to indemnify and hold harmless the developers of the Software from any related claims or disputes arising from the utilization of the Software by the user.
119
 
120
  By using the Software, you agree to the terms and conditions of the disclaimer.""")
121
-
122
  # Add a selectbox for model selection
123
  st.selectbox("Select the model to use:",
124
  ["mistralai/Mistral-7B-Instruct-v0.3",
@@ -126,44 +142,46 @@ By using the Software, you agree to the terms and conditions of the disclaimer."
126
  "HuggingFaceH4/zephyr-7b-beta"],
127
  key="my_llm_model", on_change=update_llm_model)
128
 
 
 
 
129
  # Add a text area for RAG text input
130
  st.text_area(label="Please enter your RAG text here:", value=my_initial_rag_text, height=500, key="my_rag_text", on_change=delete_chat_messages)
131
 
 
 
 
 
 
 
 
 
132
 
 
 
133
 
 
 
134
 
135
- # Define parameters
136
- min_window_size = 5 # number of sentences per chunk
137
- max_window_size = 10 # number of sentences per chunk
138
- print(100*"-")
139
- # Check if the sentences are not already in the session state
140
- if "my_sentences" not in st.session_state:
141
- text = st.session_state["my_rag_text"]
142
 
143
- # Split only on .?!;: followed by space OR on \n
144
- pattern = r'(?<=[.?!;:])\s+|\n'
145
- sentence_split = re.split(pattern, text)
146
 
147
- sentences = [s.strip() for s in sentence_split if s.strip()]
148
 
149
- # Rolling window: include partial windows at end
150
- chunks = []
151
- for rolling_window_size in range(min_window_size, max_window_size+1):
152
- for i in range(0, len(sentences)-rolling_window_size+1):
153
- chunk = " ".join(sentences[i:i+rolling_window_size]).strip()
154
- if chunk:
155
- chunks.append(chunk)
156
- print(f"*****{chunk}*****\n")
157
 
158
- st.session_state["my_sentences"] = chunks
159
- print(len(st.session_state["my_sentences"]))
160
 
 
 
 
 
161
 
162
 
163
- # Check if the embeddings are not already in the session state
164
- if "my_embeddings" not in st.session_state:
165
- st.session_state["my_embeddings"] = st.session_state["embeddings_model"].encode(st.session_state["my_sentences"])
166
-
167
  with column_2:
168
  # Create a container for the messages with a specified height
169
  messages_container = st.container(height=500)
@@ -183,29 +201,57 @@ with column_2:
183
  # Check if there is a new prompt from the user
184
  if prompt := st.chat_input("you may ask here your questions"):
185
 
186
- # Encode the user's prompt to get its embedding
187
- my_question_embedding = st.session_state.embeddings_model.encode([prompt])
 
 
 
 
 
188
 
189
- # Calculate the cosine similarity between the prompt embedding and stored embeddings
190
- similarity_to_question = cosine_similarity(my_question_embedding, st.session_state.my_embeddings).flatten()
191
-
192
- # Number of sentences to keep based on similarity
193
- nof_keep_sentences = 3
 
 
 
194
 
195
  # Get the indices of the top similar sentences
196
- sorted_indices = similarity_to_question.argsort()[::-1][:nof_keep_sentences][::-1]
197
-
198
- # Retrieve the top similar sentences
199
- sorted_sentences = ["Importance: " + str(round(100*similarity_to_question[i])) + f"% {5*'>'} " + st.session_state.my_sentences[i] for i in sorted_indices]
200
-
 
 
 
 
 
 
 
 
 
 
 
 
 
201
  # Construct the augmented prompt with the similar sentences
202
- augmented_prompt = "Here is my context:"
203
- for sentence in sorted_sentences:
204
- augmented_prompt += "\n\n" + 20*"-" + f"\n\n{sentence}"
205
- augmented_prompt += "\n\n" + 20*"-" + "\n\n" + "use the context I gave you to reply on the following:"
206
- augmented_prompt += "\n\n" + f"\n\n{prompt}"
 
 
 
 
 
 
 
 
207
 
208
-
209
  # Display the user's prompt in the chat container with a specific avatar
210
  messages_container.chat_message("user", avatar=":material/psychology_alt:").markdown(prompt)
211
  # Append the augmented prompt to the chat messages in the session state
@@ -228,14 +274,9 @@ with column_2:
228
  # Append the assistant's response to the chat messages in the session state
229
  st.session_state["my_chat_messages"].append({"role": "assistant", "content": response})
230
 
231
-
232
- # Display the chat messages history
233
- st.write("Messages History All:")
234
- st.json(st.session_state["my_chat_messages"], expanded=False)
235
- # Display the augmented prompt used for generating the response
236
- st.write("Augmented prompt:")
237
- st.json({"augmented_prompt": augmented_prompt}, expanded=False)
238
 
239
-
240
 
241
-
 
4
  import re
5
  from huggingface_hub import InferenceClient
6
  import os
7
+ import numpy as np
8
+
9
 
10
 
11
 
 
19
  - Uses Streamlit for the web interface
20
  - Employs SentenceTransformer for generating embeddings
21
  - Uses HuggingFace's InferenceClient for LLM interaction
 
22
 
23
  2. State Management:
24
  - Maintains several session state variables for:
 
84
  # We will use the all-MiniLM-L6-v2 model for embeddings
85
  st.session_state["embeddings_model"] = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')
86
 
 
87
 
88
  my_system_instructions = "You are a helpful assistant. Be brief and concise. Provide your answers in 100 words or less."
89
 
90
  first_message = "Hello, how can I help you today?"
91
 
 
 
 
 
 
 
 
92
  def delete_chat_messages():
93
  for key in st.session_state.keys():
94
+ if key != "my_rag_text" and key != "my_system_instructions":
95
  del st.session_state[key]
96
 
97
+ def create_sentences_rag():
98
+ text = st.session_state["my_rag_text"]
99
+
100
+ # Split only on .?!;: followed by space OR on \n
101
+ pattern = r'(?<=[.?!;:])\s+|\n'
102
+ st.session_state["my_sentences"] = [sentence.strip() for sentence in re.split(pattern, text) if sentence.strip()]
103
+ sentences_ids = [i for i in range(len(st.session_state["my_sentences"]))]
104
+
105
+ # Rolling window: include partial windows at end
106
+ st.session_state["my_sentences_rag_ids"] = []
107
+ st.session_state["my_sentences_rag"] = []
108
+ for rolling_window_size in range(st.session_state["min_window_size"], st.session_state["max_window_size"]+1):
109
+ for i in range(0, len(st.session_state["my_sentences"])-rolling_window_size+1):
110
+ chunk = " ".join(st.session_state["my_sentences"][i:i+rolling_window_size]).strip()
111
+ if chunk:
112
+ st.session_state["my_sentences_rag"].append(chunk)
113
+ st.session_state["my_sentences_rag_ids"].append(sentences_ids[i:i+rolling_window_size])
114
+ # print(f"*****{chunk}*****\n")
115
+
116
+ print(len(st.session_state["my_sentences_rag"]))
117
+ st.session_state["my_embeddings"] = st.session_state["embeddings_model"].encode(st.session_state["my_sentences_rag"])
118
+
119
+
120
  augmented_prompt = ""
121
 
122
  # Create two columns with a 1:2 ratio
 
134
  The user agrees to indemnify and hold harmless the developers of the Software from any related claims or disputes arising from the utilization of the Software by the user.
135
 
136
  By using the Software, you agree to the terms and conditions of the disclaimer.""")
137
+
138
  # Add a selectbox for model selection
139
  st.selectbox("Select the model to use:",
140
  ["mistralai/Mistral-7B-Instruct-v0.3",
 
142
  "HuggingFaceH4/zephyr-7b-beta"],
143
  key="my_llm_model", on_change=update_llm_model)
144
 
145
+ # Add a text are for the system instructions
146
+ st.text_area(label="Please enter your system instructions here:", value=my_system_instructions, height=100, key="my_system_instructions", on_change=delete_chat_messages)
147
+
148
  # Add a text area for RAG text input
149
  st.text_area(label="Please enter your RAG text here:", value=my_initial_rag_text, height=500, key="my_rag_text", on_change=delete_chat_messages)
150
 
151
+ # Add a slider for minimum window size
152
+ st.slider("Minimum window size in original sentences", min_value=1, max_value=20, value=5, step=1, key="min_window_size", on_change=create_sentences_rag)
153
+
154
+ # Add a slider for maximum window size
155
+ st.slider("Maximum window size in original sentences", min_value=1, max_value=20, value=10, step=1, key="max_window_size", on_change=create_sentences_rag)
156
+
157
+ # Add a slider for the similarity threshold
158
+ st.slider("Similarity threshold", min_value=0.0, max_value=1.0, value=0.3, step=0.01, key="my_similarity_threshold")
159
 
160
+ # Add a slider for the number of sentences to keep
161
+ st.slider("Number of original chunks to keep", min_value=1, max_value=50, value=20, step=1, key="nof_keep_sentences")
162
 
163
+ # Add a slider for the number of minimum sub prompts
164
+ st.slider("Minimum number of words in sub prompt split", min_value=1, max_value=10, value=1, step=1, key="nof_min_sub_prompts")
165
 
166
+ # Add a slider for the number of maximum sub prompts
167
+ st.slider("Maximum number of words in sub prompt split", min_value=1, max_value=10, value=5, step=1, key="nof_max_sub_prompts")
 
 
 
 
 
168
 
 
 
 
169
 
 
170
 
171
+ # Check if the chat messages are not already in the session state
172
+ if "my_chat_messages" not in st.session_state:
173
+ # Initialize the chat messages list in the session state
174
+ st.session_state["my_chat_messages"] = []
175
+ # Add the system instructions to the chat messages
176
+ st.session_state["my_chat_messages"].append({"role": "system", "content": st.session_state["my_system_instructions"]})
 
 
177
 
 
 
178
 
179
+ # print(100*"-")
180
+ # Check if the sentences are not already in the session state
181
+ if "my_sentences_rag" not in st.session_state:
182
+ create_sentences_rag()
183
 
184
 
 
 
 
 
185
  with column_2:
186
  # Create a container for the messages with a specified height
187
  messages_container = st.container(height=500)
 
201
  # Check if there is a new prompt from the user
202
  if prompt := st.chat_input("you may ask here your questions"):
203
 
204
+ split_prompt = prompt.split(" ")
205
+ all_sub_prompts = []
206
+ for jj in range(st.session_state["nof_min_sub_prompts"], st.session_state["nof_max_sub_prompts"]+1):
207
+ for ii in range(len(split_prompt)):
208
+ i_split = " ".join(split_prompt[ii:ii+jj]).strip()
209
+ if i_split:
210
+ all_sub_prompts.append(i_split)
211
 
212
+ similarities_to_question = np.zeros(len(st.session_state["my_embeddings"]))
213
+ for sub_prompt in all_sub_prompts:
214
+ # Encode the user's prompt to get its embedding
215
+ my_question_embedding = st.session_state.embeddings_model.encode([sub_prompt])
216
+
217
+ # Calculate the cosine similarity between the prompt embedding and stored embeddings
218
+ similarities_to_question += cosine_similarity(my_question_embedding, st.session_state["my_embeddings"]).flatten()
219
+ similarities_to_question /= len(all_sub_prompts)
220
 
221
  # Get the indices of the top similar sentences
222
+ bottom_col1, bottom_col2 = st.columns([1, 1])
223
+ sorted_indices_rag = similarities_to_question.argsort()[::-1]
224
+ sorted_indices_sentences = []
225
+ max_similarity = 0
226
+ # for irag in range(st.session_state["nof_keep_sentences"]):
227
+ irag = 0
228
+ while len(set(sorted_indices_sentences))<st.session_state["nof_keep_sentences"]:
229
+ sorted_indices_sentences.extend(st.session_state["my_sentences_rag_ids"][sorted_indices_rag[irag]])
230
+ max_similarity = max(max_similarity, similarities_to_question[sorted_indices_rag[irag]])
231
+ with bottom_col1:
232
+ str_conf = f"Confidence: {similarities_to_question[sorted_indices_rag[irag]]:.5f}, Sentences IDs: {st.session_state["my_sentences_rag_ids"][sorted_indices_rag[irag]]}"
233
+ with st.expander(f"Chunk: {str(irag+1)} {str_conf}"):
234
+ for idx in st.session_state["my_sentences_rag_ids"][sorted_indices_rag[irag]]:
235
+ st.write(f"{st.session_state["my_sentences"][idx]}")
236
+ irag += 1
237
+
238
+ sorted_indices_sentences = sorted(list(set(sorted_indices_sentences)))
239
+
240
  # Construct the augmented prompt with the similar sentences
241
+ if max_similarity > st.session_state["my_similarity_threshold"]:
242
+ augmented_prompt = "This is my context:" + "\n\n" + 20*"-" + "\n\n"
243
+ augmented_prompt += "\n".join([st.session_state["my_sentences"][idx] for idx in sorted_indices_sentences])
244
+ augmented_prompt += "\n\n" + 20*"-" + "\n\n" + "If the above context is not relevant to the prompt, ignore the context and reply based only on the prompt."
245
+ augmented_prompt += "\n\n" + 20*"-" + "\n\n" + "If the above context is relevant to the prompt, reply based on the context and the prompt."
246
+ augmented_prompt += "\n\n" + 20*"-" + "\n\n" + "The prompt is:"
247
+ augmented_prompt += "\n\n" + f"\n\n{prompt}"
248
+ else:
249
+ augmented_prompt = prompt
250
+ with bottom_col2:
251
+ # Display the augmented prompt used for generating the response
252
+ st.write("Augmented prompt:")
253
+ st.json({"max_similarity": max_similarity, "augmented_prompt": augmented_prompt}, expanded=False)
254
 
 
255
  # Display the user's prompt in the chat container with a specific avatar
256
  messages_container.chat_message("user", avatar=":material/psychology_alt:").markdown(prompt)
257
  # Append the augmented prompt to the chat messages in the session state
 
274
  # Append the assistant's response to the chat messages in the session state
275
  st.session_state["my_chat_messages"].append({"role": "assistant", "content": response})
276
 
277
+ with bottom_col2:
278
+ # Display the chat messages history
279
+ st.write("Messages History All:")
280
+ st.json(st.session_state["my_chat_messages"], expanded=False)
 
 
 
281
 
 
282