Spaces:
Sleeping
Sleeping
File size: 16,000 Bytes
fc3ddc9 f25e2d7 a566f09 f25e2d7 fc3ddc9 207b9f8 fc3ddc9 a566f09 fc3ddc9 fe6e823 7a1339e fc3ddc9 e87e726 a566f09 fc3ddc9 e87e726 fc3ddc9 a566f09 fc3ddc9 a566f09 fc3ddc9 e87e726 fc3ddc9 9697155 fc3ddc9 bcf1ca1 fc3ddc9 a566f09 fc3ddc9 f25e2d7 a566f09 f25e2d7 a566f09 f25e2d7 fc3ddc9 f25e2d7 fc3ddc9 0d1a7d8 fc3ddc9 f25e2d7 a566f09 f25e2d7 a566f09 fc3ddc9 a566f09 fc3ddc9 f25e2d7 a566f09 207b9f8 f25e2d7 207b9f8 f25e2d7 207b9f8 f25e2d7 207b9f8 f25e2d7 e87e726 f25e2d7 e87e726 207b9f8 f25e2d7 207b9f8 fc3ddc9 a566f09 fc3ddc9 e87e726 fc3ddc9 e87e726 fc3ddc9 e87e726 fc3ddc9 a566f09 f25e2d7 a566f09 e87e726 f25e2d7 a566f09 f25e2d7 fc3ddc9 e87e726 f25e2d7 e87e726 f25e2d7 fc3ddc9 f25e2d7 e87e726 f25e2d7 a566f09 e87e726 f25e2d7 e87e726 f25e2d7 e87e726 f25e2d7 fc3ddc9 a566f09 fc3ddc9 a566f09 fc3ddc9 e87e726 fc3ddc9 e87e726 fc3ddc9 a566f09 f25e2d7 a566f09 f25e2d7 a566f09 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 | import streamlit as st
from sentence_transformers import SentenceTransformer
from sklearn.metrics.pairwise import cosine_similarity
import re
from huggingface_hub import InferenceClient
import os
import numpy as np
from openai import OpenAI
st.set_page_config(layout="wide")
with open("/home/user/app/labeled_text_small.txt", "r", encoding="utf-8") as f:
my_initial_rag_text = f.read()
# Check if the LLM model is not already in the session state
if "my_llm_model" not in st.session_state:
# Set the default LLM model to "mistralai/Mistral-7B-Instruct-v0.3"
st.session_state['my_llm_model'] = "mistralai/Mistral-7B-Instruct-v0.3"
# Check if the SPACE_ID environment variable is not already in the session state
if "my_space" not in st.session_state:
st.session_state['my_space'] = os.environ.get("SPACE_ID")
# Function to update the LLM model client
def update_llm_model():
if st.session_state['my_llm_model'].startswith("gemini-"):
# Initialize the client for gemini models. We use the OpenAI API to interact with gemini models.
st.session_state['client'] = OpenAI(api_key = os.getenv("GOOGLE_API_KEY"),
base_url = "https://generativelanguage.googleapis.com/v1beta/openai/")
elif st.session_state['my_llm_model'].startswith("gpt-"):
# Initialize the client for openai models
st.session_state['client'] = OpenAI(api_key = os.getenv("OPENAI_API_KEY"))
# ,base_url = "https://eu.api.openai.com/" # gives error
else:
if st.session_state['my_space']:
# Initialize the client with the model if SPACE_ID is available
st.session_state['client'] = InferenceClient(st.session_state['my_llm_model'])
else:
# Initialize the client with the model and token if SPACE_ID is not available
st.session_state['client'] = InferenceClient(st.session_state['my_llm_model'], token=os.getenv("HF_TOKEN"))
# Check if the client is not already in the session state
if "client" not in st.session_state:
update_llm_model()
# Check if the embeddings model is not already in the session state
if "embeddings_model" not in st.session_state:
# We will use the all-MiniLM-L6-v2 model for embeddings
st.session_state['embeddings_model'] = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')
my_system_instructions = "You are a helpful assistant. Be brief and concise. ALWAYS clasify given text as FAKE or REAL based on the given context using 100 words or less."
first_message = "Hello, how can I help you today?"
def delete_chat_messages():
for key in list(st.session_state.keys()):
if key not in {"my_rag_text", "my_system_instructions", "my_llm_model", "my_space"}:
del st.session_state[key]
update_llm_model()
def create_sentences_rag():
with rag_status_placeholder:
# The pattern splits text at any of the punctuation marks .?!;: followed by one or more spaces, or at a newline character
pattern = r'(?<=[.?!;:])\s+|\n'
st.session_state['my_sentences'] = [sentence.strip() for sentence in re.split(pattern, st.session_state['my_rag_text']) if sentence.strip()]
with st.spinner(f"Encoding {len(st.session_state['my_sentences'])} sentences..."):
sentences_ids = [i for i in range(len(st.session_state['my_sentences']))]
# Rolling window: include partial windows at end
st.session_state['my_sentences_rag_ids'] = []
st.session_state['my_sentences_rag'] = []
for rolling_window_size in range(st.session_state['min_window_size'], st.session_state['max_window_size']+1):
for i in range(0, len(st.session_state['my_sentences'])-rolling_window_size+1):
chunk = " ".join(st.session_state['my_sentences'][i:i+rolling_window_size]).strip()
if chunk:
st.session_state['my_sentences_rag'].append(chunk)
st.session_state['my_sentences_rag_ids'].append(sentences_ids[i:i+rolling_window_size])
# print(f"*****{chunk}*****\n")
st.session_state['my_embeddings'] = st.session_state['embeddings_model'].encode(st.session_state['my_sentences_rag'])
st.success(f"{len(st.session_state['my_sentences_rag'])} chunks have been encoded!")
# Create two columns with a 1:2 ratio
column_1, column_2 = st.columns([1, 2])
# In the first column
with column_1:
# Display a disclaimer about the potential inaccuracies of Large Language Models
st.expander("Disclaimer", expanded=False).markdown("""This application and code (hereafter referred to as the 'Software') is a proof of concept at an experimental stage and is not intended to be used as a production environment. The Software is provided as is, wihtout any warranties of any kind, expressed or implied and the user assumes full responsibility for its use, implementation, and legal compliance.
The developers of the Software shall not be liable for any damages, losses, claims, or liabilities arising from the Software, including but not limited to the usage of artificial intelligence and machine learning, related errors, third-party tool failures, security breaches, intellectual property violations, legal or regulatory non-compliance, deployment risks, or any indirect, incidental, or consequential damages.
Large Language Models may provide wrong answers. Please verify the answers and comply with applicable laws and regulations.
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.
By using the Software, you agree to the terms and conditions of the disclaimer.""")
# Add a selectbox for model selection
# model_list_all = [ 'mistralai/Mistral-7B-Instruct-v0.3',
# 'Qwen/Qwen2.5-72B-Instruct',
# 'HuggingFaceH4/zephyr-7b-beta']
# if os.getenv("GOOGLE_API_KEY"):
# model_list_all.append('gemini-2.5-flash-preview-05-20')
# if os.getenv("OPENAI_API_KEY"):
# model_list_all.append('gpt-4.1-nano-2025-04-14')
# st.selectbox("Select the model to use:",
# model_list_all,
# key="my_llm_model",
# on_change=update_llm_model)
# Add a text are for the system instructions
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)
# Placeholder right after text_area
rag_status_placeholder = st.empty()
# Add a text area for RAG text input
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)
# Add a slider for minimum window size
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)
# Add a slider for maximum window size
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)
# Add a slider for the similarity threshold
st.slider("Similarity threshold", min_value=0.0, max_value=1.0, value=0.2, step=0.01, key="my_similarity_threshold")
# Add a slider for the number of sentences to keep
st.slider("Number of original chunks to keep", min_value=1, max_value=50, value=20, step=1, key="nof_keep_sentences")
# Add a slider for the number of minimum sub prompts
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")
# Add a slider for the number of maximum sub prompts
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")
# Check if the chat messages are not already in the session state
if "my_chat_messages" not in st.session_state:
# Initialize the chat messages list in the session state
st.session_state['my_chat_messages'] = []
# Add the system instructions to the chat messages
st.session_state['my_chat_messages'].append({"role": "system", "content": st.session_state['my_system_instructions']})
# print(100*"-")
# Check if the sentences are not already in the session state
if "my_sentences_rag" not in st.session_state:
create_sentences_rag()
with column_2:
# Create a container for the messages with a specified height
messages_container = st.container(height=500)
# Display the first message from the assistant
messages_container.chat_message("ai", avatar=":material/robot_2:").markdown(first_message)
# Iterate through the chat messages stored in the session state
for message in st.session_state['my_chat_messages']:
if message['role'] == "user":
# Display user messages with a specific avatar - https://fonts.google.com/icons
messages_container.chat_message(message['role'], avatar=":material/psychology_alt:").markdown(message['content'])
elif message['role'] == "assistant":
# Display assistant messages with a specific avatar
messages_container.chat_message(message['role'], avatar=":material/robot_2:").markdown(message['content'])
# Check if there is a new prompt from the user
if prompt := st.chat_input("you may ask here your questions"):
# Split the prompt into words
split_prompt = prompt.split(" ")
all_sub_prompts = []
# Generate sub-prompts based on the specified range
for jj in range(st.session_state['nof_min_sub_prompts'], st.session_state['nof_max_sub_prompts']+1):
for ii in range(len(split_prompt)):
# Create sub-prompt by joining words
i_split = " ".join(split_prompt[ii:ii+jj]).strip()
if i_split:
all_sub_prompts.append(i_split)
similarities_to_question = np.zeros(len(st.session_state['my_embeddings']))
for sub_prompt in all_sub_prompts:
# Encode the user's prompt to get its embedding
my_question_embedding = st.session_state.embeddings_model.encode([sub_prompt])
# Calculate the cosine similarity between the prompt embedding and stored embeddings
similarities_to_question += cosine_similarity(my_question_embedding, st.session_state['my_embeddings']).flatten()
similarities_to_question /= len(all_sub_prompts)
# Get the indices of the top similar sentences
bottom_col1, bottom_col2 = st.columns([1, 1])
sorted_indices_rag = similarities_to_question.argsort()[::-1]
sorted_indices_sentences = []
max_similarity = 0
# for irag in range(st.session_state['nof_keep_sentences']):
irag = 0
while len(set(sorted_indices_sentences))<st.session_state['nof_keep_sentences'] and irag<len(sorted_indices_rag):
sorted_indices_sentences.extend(st.session_state['my_sentences_rag_ids'][sorted_indices_rag[irag]])
max_similarity = max(max_similarity, similarities_to_question[sorted_indices_rag[irag]])
with bottom_col1:
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]]}"
with st.expander(f"Chunk: {str(irag+1)} {str_conf}"):
for idx in st.session_state['my_sentences_rag_ids'][sorted_indices_rag[irag]]:
st.write(f"{st.session_state['my_sentences'][idx]}")
irag += 1
sorted_indices_sentences = sorted(list(set(sorted_indices_sentences)))
# Display the user's prompt in the chat container with a specific avatar
messages_container.chat_message("user", avatar=":material/psychology_alt:").markdown(prompt)
# Create an empty container for the streaming response from the assistant
with messages_container.chat_message("ai", avatar=":material/robot_2:"):
response_placeholder = st.empty()
if max_similarity > st.session_state['my_similarity_threshold']:
# Construct the augmented prompt with the similar sentences
augmented_prompt = "This is my context:" + "\n\n" + 20*"-" + "\n\n"
augmented_prompt += "\n".join([st.session_state['my_sentences'][idx] for idx in sorted_indices_sentences])
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."
augmented_prompt += "\n\n" + 20*"-" + "\n\n" + "If the above context is relevant to the prompt, reply based on the context and the prompt."
augmented_prompt += "\n\n" + 20*"-" + "\n\n" + "The prompt is:"
augmented_prompt += "\n\n" + f"\n\n{prompt}"
# Append the augmented prompt to the chat messages in the session state
st.session_state['my_chat_messages'].append({"role": "user", "content": augmented_prompt})
# Stream the response from the assistant and update the placeholder
response = ""
for chunk in st.session_state['client'].chat.completions.create(messages = st.session_state['my_chat_messages'],
model = st.session_state['my_llm_model'],
stream = True,
max_tokens = 1024):
if chunk.choices[0].delta.content:
response += chunk.choices[0].delta.content
# Use markdown to update the response placeholder with the streamed content
response_placeholder.markdown(response)
# Remove the last message from the chat messages in the session state
st.session_state['my_chat_messages'].pop()
else:
augmented_prompt = ""
response = f"I do not have enough information to reply. The maximum similarity found in the context is: {100*max_similarity:.2f}%."
response_placeholder.markdown(response)
# Append the user's original prompt to the chat messages in the session state
st.session_state['my_chat_messages'].append({"role": "user", "content": prompt})
# Append the assistant's response to the chat messages in the session state
st.session_state['my_chat_messages'].append({"role": "assistant", "content": response})
if len(st.session_state['my_chat_messages'])>10:
# Keep the first message which is the system instructions, remove the 2nd and 3rd messages which are the first user and assistant messages
st.session_state['my_chat_messages'] = st.session_state['my_chat_messages'][:1] + st.session_state['my_chat_messages'][3:]
with bottom_col2:
# Display the augmented prompt used for generating the response
st.write("Augmented prompt:")
st.json({"max_similarity": max_similarity, "augmented_prompt": augmented_prompt}, expanded=False)
# Display the chat messages history
st.write("Messages History All:")
st.json(st.session_state['my_chat_messages'], expanded=False)
|