nibas commited on
Commit
a566f09
·
verified ·
1 Parent(s): f36cc75

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +100 -62
app.py CHANGED
@@ -5,12 +5,13 @@ import re
5
  from huggingface_hub import InferenceClient
6
  import os
7
  import numpy as np
 
8
 
9
 
10
 
11
 
12
- st.set_page_config(layout="wide")
13
 
 
14
 
15
 
16
  my_initial_rag_text = f"""This is a RAG (Retrieval-Augmented Generation) chatbot application built with Streamlit that combines document context with LLM responses. Here's a breakdown of its main components:
@@ -62,18 +63,28 @@ A disclaimer at the bottom reminds users about potential LLM inaccuracies and th
62
  if "my_llm_model" not in st.session_state:
63
  # Set the default LLM model to "mistralai/Mistral-7B-Instruct-v0.3"
64
  st.session_state['my_llm_model'] = "mistralai/Mistral-7B-Instruct-v0.3"
 
65
  # Check if the SPACE_ID environment variable is not already in the session state
66
  if "my_space" not in st.session_state:
67
  st.session_state['my_space'] = os.environ.get("SPACE_ID")
68
 
69
  # Function to update the LLM model client
70
  def update_llm_model():
71
- if st.session_state['my_space']:
72
- # Initialize the client with the model if SPACE_ID is available
73
- st.session_state['client'] = InferenceClient(st.session_state['my_llm_model'])
 
 
 
 
 
74
  else:
75
- # Initialize the client with the model and token if SPACE_ID is not available
76
- st.session_state['client'] = InferenceClient(st.session_state['my_llm_model'], token=os.getenv("HF_TOKEN"))
 
 
 
 
77
 
78
  # Check if the client is not already in the session state
79
  if "client" not in st.session_state:
@@ -84,7 +95,6 @@ if "embeddings_model" not in st.session_state:
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?"
@@ -93,32 +103,33 @@ 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
123
  column_1, column_2 = st.columns([1, 2])
124
 
@@ -136,17 +147,25 @@ The user agrees to indemnify and hold harmless the developers of the Software fr
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',
141
- 'Qwen/Qwen2.5-72B-Instruct',
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)
@@ -155,7 +174,7 @@ By using the Software, you agree to the terms and conditions of the disclaimer."
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")
@@ -182,6 +201,8 @@ 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,10 +222,13 @@ with column_2:
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)
@@ -225,7 +249,7 @@ with column_2:
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:
@@ -237,44 +261,58 @@ with column_2:
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
258
- st.session_state['my_chat_messages'].append({"role": "user", "content": augmented_prompt})
259
  # Create an empty container for the streaming response from the assistant
260
  with messages_container.chat_message("ai", avatar=":material/robot_2:"):
261
  response_placeholder = st.empty()
262
- response = ""
263
- # Stream the response from the assistant and update the placeholder
264
- for chunk in st.session_state['client'].chat.completions.create(messages=st.session_state['my_chat_messages'], stream=True, max_tokens=512):
265
- if chunk.choices[0].delta.content:
266
- response += chunk.choices[0].delta.content
267
- # Use markdown to update the response placeholder with the streamed content
268
- response_placeholder.markdown(response)
269
-
270
- # Remove the last message from the chat messages in the session state
271
- st.session_state['my_chat_messages'].pop()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
272
  # Append the user's original prompt to the chat messages in the session state
273
  st.session_state['my_chat_messages'].append({"role": "user", "content": prompt})
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)
 
 
 
5
  from huggingface_hub import InferenceClient
6
  import os
7
  import numpy as np
8
+ from openai import OpenAI
9
 
10
 
11
 
12
 
 
13
 
14
+ st.set_page_config(layout="wide")
15
 
16
 
17
  my_initial_rag_text = f"""This is a RAG (Retrieval-Augmented Generation) chatbot application built with Streamlit that combines document context with LLM responses. Here's a breakdown of its main components:
 
63
  if "my_llm_model" not in st.session_state:
64
  # Set the default LLM model to "mistralai/Mistral-7B-Instruct-v0.3"
65
  st.session_state['my_llm_model'] = "mistralai/Mistral-7B-Instruct-v0.3"
66
+
67
  # Check if the SPACE_ID environment variable is not already in the session state
68
  if "my_space" not in st.session_state:
69
  st.session_state['my_space'] = os.environ.get("SPACE_ID")
70
 
71
  # Function to update the LLM model client
72
  def update_llm_model():
73
+ if st.session_state['my_llm_model'].startswith("gemini-"):
74
+ # Initialize the client for gemini models. We use the OpenAI API to interact with gemini models.
75
+ st.session_state['client'] = OpenAI(api_key = os.getenv("GOOGLE_API_KEY"),
76
+ base_url = "https://generativelanguage.googleapis.com/v1beta/openai/")
77
+ elif st.session_state['my_llm_model'].startswith("gpt-"):
78
+ # Initialize the client for openai models
79
+ st.session_state['client'] = OpenAI(api_key = os.getenv("OPENAI_API_KEY"))
80
+ # ,base_url = "https://eu.api.openai.com/" # gives error
81
  else:
82
+ if st.session_state['my_space']:
83
+ # Initialize the client with the model if SPACE_ID is available
84
+ st.session_state['client'] = InferenceClient(st.session_state['my_llm_model'])
85
+ else:
86
+ # Initialize the client with the model and token if SPACE_ID is not available
87
+ st.session_state['client'] = InferenceClient(st.session_state['my_llm_model'], token=os.getenv("HF_TOKEN"))
88
 
89
  # Check if the client is not already in the session state
90
  if "client" not in st.session_state:
 
95
  # We will use the all-MiniLM-L6-v2 model for embeddings
96
  st.session_state['embeddings_model'] = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')
97
 
 
98
  my_system_instructions = "You are a helpful assistant. Be brief and concise. Provide your answers in 100 words or less."
99
 
100
  first_message = "Hello, how can I help you today?"
 
103
  for key in st.session_state.keys():
104
  if key != "my_rag_text" and key != "my_system_instructions":
105
  del st.session_state[key]
106
+ update_llm_model()
107
+
108
 
109
  def create_sentences_rag():
110
+ with rag_status_placeholder:
111
+ # The pattern splits text at any of the punctuation marks .?!;: followed by one or more spaces, or at a newline character
112
+ pattern = r'(?<=[.?!;:])\s+|\n'
113
+ st.session_state['my_sentences'] = [sentence.strip() for sentence in re.split(pattern, st.session_state['my_rag_text']) if sentence.strip()]
114
+ with st.spinner(f"Encoding {len(st.session_state['my_sentences'])} sentences..."):
115
+ sentences_ids = [i for i in range(len(st.session_state['my_sentences']))]
116
+ # Rolling window: include partial windows at end
117
+ st.session_state['my_sentences_rag_ids'] = []
118
+ st.session_state['my_sentences_rag'] = []
119
+ for rolling_window_size in range(st.session_state['min_window_size'], st.session_state['max_window_size']+1):
120
+ for i in range(0, len(st.session_state['my_sentences'])-rolling_window_size+1):
121
+ chunk = " ".join(st.session_state['my_sentences'][i:i+rolling_window_size]).strip()
122
+ if chunk:
123
+ st.session_state['my_sentences_rag'].append(chunk)
124
+ st.session_state['my_sentences_rag_ids'].append(sentences_ids[i:i+rolling_window_size])
125
+ # print(f"*****{chunk}*****\n")
126
 
127
+ st.session_state['my_embeddings'] = st.session_state['embeddings_model'].encode(st.session_state['my_sentences_rag'])
128
+ st.success(f"{len(st.session_state['my_sentences_rag'])} chunks have been encoded!")
 
 
129
 
 
 
 
 
 
 
 
 
 
 
130
 
 
 
131
 
132
 
 
 
133
  # Create two columns with a 1:2 ratio
134
  column_1, column_2 = st.columns([1, 2])
135
 
 
147
  By using the Software, you agree to the terms and conditions of the disclaimer.""")
148
 
149
  # Add a selectbox for model selection
150
+ model_list_all = [ 'mistralai/Mistral-7B-Instruct-v0.3',
151
+ 'Qwen/Qwen2.5-72B-Instruct',
152
+ 'HuggingFaceH4/zephyr-7b-beta']
153
+ if os.getenv("GOOGLE_API_KEY"):
154
+ model_list_all.append('gemini-2.5-flash-preview-05-20')
155
+ if os.getenv("OPENAI_API_KEY"):
156
+ model_list_all.append('gpt-4.1-nano-2025-04-14')
157
  st.selectbox("Select the model to use:",
158
+ model_list_all,
159
+ key="my_llm_model",
160
+ on_change=update_llm_model)
 
161
 
162
  # Add a text are for the system instructions
163
+ st.text_area(label="Please enter your system instructions here:", value=my_system_instructions, height=80, key="my_system_instructions", on_change=delete_chat_messages)
164
 
165
+ # Placeholder right after text_area
166
+ rag_status_placeholder = st.empty()
167
  # Add a text area for RAG text input
168
+ st.text_area(label="Please enter your RAG text here:", value=my_initial_rag_text, height=200, key="my_rag_text", on_change=delete_chat_messages)
169
 
170
  # Add a slider for minimum window size
171
  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)
 
174
  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)
175
 
176
  # Add a slider for the similarity threshold
177
+ st.slider("Similarity threshold", min_value=0.0, max_value=1.0, value=0.2, step=0.01, key="my_similarity_threshold")
178
 
179
  # Add a slider for the number of sentences to keep
180
  st.slider("Number of original chunks to keep", min_value=1, max_value=50, value=20, step=1, key="nof_keep_sentences")
 
201
  create_sentences_rag()
202
 
203
 
204
+
205
+
206
  with column_2:
207
  # Create a container for the messages with a specified height
208
  messages_container = st.container(height=500)
 
222
  # Check if there is a new prompt from the user
223
  if prompt := st.chat_input("you may ask here your questions"):
224
 
225
+ # Split the prompt into words
226
  split_prompt = prompt.split(" ")
227
  all_sub_prompts = []
228
+ # Generate sub-prompts based on the specified range
229
  for jj in range(st.session_state['nof_min_sub_prompts'], st.session_state['nof_max_sub_prompts']+1):
230
  for ii in range(len(split_prompt)):
231
+ # Create sub-prompt by joining words
232
  i_split = " ".join(split_prompt[ii:ii+jj]).strip()
233
  if i_split:
234
  all_sub_prompts.append(i_split)
 
249
  max_similarity = 0
250
  # for irag in range(st.session_state['nof_keep_sentences']):
251
  irag = 0
252
+ while len(set(sorted_indices_sentences))<st.session_state['nof_keep_sentences'] and irag<len(sorted_indices_rag):
253
  sorted_indices_sentences.extend(st.session_state['my_sentences_rag_ids'][sorted_indices_rag[irag]])
254
  max_similarity = max(max_similarity, similarities_to_question[sorted_indices_rag[irag]])
255
  with bottom_col1:
 
261
 
262
  sorted_indices_sentences = sorted(list(set(sorted_indices_sentences)))
263
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
264
  # Display the user's prompt in the chat container with a specific avatar
265
  messages_container.chat_message("user", avatar=":material/psychology_alt:").markdown(prompt)
266
+
 
267
  # Create an empty container for the streaming response from the assistant
268
  with messages_container.chat_message("ai", avatar=":material/robot_2:"):
269
  response_placeholder = st.empty()
270
+ if max_similarity > st.session_state['my_similarity_threshold']:
271
+ # Construct the augmented prompt with the similar sentences
272
+ augmented_prompt = "This is my context:" + "\n\n" + 20*"-" + "\n\n"
273
+ augmented_prompt += "\n".join([st.session_state['my_sentences'][idx] for idx in sorted_indices_sentences])
274
+ 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."
275
+ augmented_prompt += "\n\n" + 20*"-" + "\n\n" + "If the above context is relevant to the prompt, reply based on the context and the prompt."
276
+ augmented_prompt += "\n\n" + 20*"-" + "\n\n" + "The prompt is:"
277
+ augmented_prompt += "\n\n" + f"\n\n{prompt}"
278
+ # Append the augmented prompt to the chat messages in the session state
279
+ st.session_state['my_chat_messages'].append({"role": "user", "content": augmented_prompt})
280
+ # Stream the response from the assistant and update the placeholder
281
+ response = ""
282
+ for chunk in st.session_state['client'].chat.completions.create(messages = st.session_state['my_chat_messages'],
283
+ model = st.session_state['my_llm_model'],
284
+ stream = True,
285
+ max_tokens = 1024):
286
+ if chunk.choices[0].delta.content:
287
+ response += chunk.choices[0].delta.content
288
+ # Use markdown to update the response placeholder with the streamed content
289
+ response_placeholder.markdown(response)
290
+ # Remove the last message from the chat messages in the session state
291
+ st.session_state['my_chat_messages'].pop()
292
+ else:
293
+ augmented_prompt = ""
294
+ response = f"I do not have enough information to reply. The maximum similarity found in the context is: {100*max_similarity:.2f}%."
295
+ response_placeholder.markdown(response)
296
+
297
  # Append the user's original prompt to the chat messages in the session state
298
  st.session_state['my_chat_messages'].append({"role": "user", "content": prompt})
299
  # Append the assistant's response to the chat messages in the session state
300
  st.session_state['my_chat_messages'].append({"role": "assistant", "content": response})
301
 
302
+
303
+ if len(st.session_state['my_chat_messages'])>10:
304
+ # Keep the first message which is the system instructions, remove the 2nd and 3rd messages which are the first user and assistant messages
305
+ st.session_state['my_chat_messages'] = st.session_state['my_chat_messages'][:1] + st.session_state['my_chat_messages'][3:]
306
+
307
+
308
+
309
  with bottom_col2:
310
+ # Display the augmented prompt used for generating the response
311
+ st.write("Augmented prompt:")
312
+ st.json({"max_similarity": max_similarity, "augmented_prompt": augmented_prompt}, expanded=False)
313
+
314
  # Display the chat messages history
315
  st.write("Messages History All:")
316
+ st.json(st.session_state['my_chat_messages'], expanded=False)
317
+
318
+