File size: 7,185 Bytes
9bc4ec7 07d1254 9bc4ec7 59321ff 07d1254 9bc4ec7 4c4dd9e 59321ff 4c4dd9e 59321ff 4c4dd9e 9bc4ec7 59321ff 9bc4ec7 59321ff 9bc4ec7 59321ff 9bc4ec7 59321ff 9bc4ec7 |
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 |
import streamlit as st
import os
import requests
from dotenv import load_dotenv # Only needed if using a .env file
import re # To help clean up leading whitespace
# Langchain and HuggingFace
from langchain.vectorstores import Chroma
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_groq import ChatGroq
from langchain.chains import RetrievalQA
# Load the .env file (if using it)
load_dotenv()
groq_api_key = os.getenv("GROQ_API_KEY")
# Load embeddings, model, and vector store
@st.cache_resource # Singleton, prevent multiple initializations
def init_chain():
model_kwargs = {'trust_remote_code': True}
embedding = HuggingFaceEmbeddings(model_name='nomic-ai/nomic-embed-text-v1.5', model_kwargs=model_kwargs)
llm = ChatGroq(groq_api_key=groq_api_key, model_name="llama3-70b-8192", temperature=0.2)
vectordb = Chroma(persist_directory='updated_CSPCDB2', embedding_function=embedding)
# Create chain
chain = RetrievalQA.from_chain_type(llm=llm,
chain_type="stuff",
retriever=vectordb.as_retriever(k=5),
return_source_documents=True)
return chain
# Streamlit app layout
st.set_page_config(
page_title="CSPC Citizens Charter Conversational Agent",
page_icon="cspclogo.png"
)
with st.sidebar:
st.title('CSPCean Conversational Agent')
st.subheader('Ask anything CSPC Related here!')
st.markdown('''**About CSPC:**
History, Core Values, Mission and Vision''')
st.markdown('''**Admission & Graduation:**
Apply, Requirements, Process, Graduation''')
st.markdown('''**Student Services:**
Scholarships, Orgs, Facilities''')
st.markdown('''**Academics:**
Degrees, Courses, Faculty''')
st.markdown('''**Officials:**
President, VPs, Deans, Admin''')
st.markdown('''
Access the resources here:
- [CSPC Citizen’s Charter](https://cspc.edu.ph/governance/citizens-charter/)
- [About CSPC](https://cspc.edu.ph/about/)
- [College Officials](https://cspc.edu.ph/college-officials/)
''')
st.markdown('Team XceptionNet')
# Store LLM generated responses
if "messages" not in st.session_state:
st.session_state.chain = init_chain()
st.session_state.messages = [{"role": "assistant", "content": "How may I help you today?"}]
st.session_state.query_counter = 0 # Track the number of user queries
st.session_state.conversation_history = "" # Keep track of history for the LLM
def generate_response(prompt_input):
try:
# Retrieve vector database context using ONLY the current user input
retriever = st.session_state.chain.retriever
relevant_context = retriever.get_relevant_documents(prompt_input) # Retrieve context only for the current prompt
# Format the input for the chain with the retrieved context
formatted_input = (
f"Context:\n"
f"{' '.join([doc.page_content for doc in relevant_context])}\n\n"
f"Conversation:\n{st.session_state.conversation_history}user: {prompt_input}\n"
)
# Invoke the RetrievalQA chain directly with the formatted input
res = st.session_state.chain.invoke({"query": formatted_input})
# Process the response text
result_text = res['result']
# Clean up prefixing phrases and capitalize the first letter
if result_text.startswith('According to the provided context, '):
result_text = result_text[35:].strip()
elif result_text.startswith('Based on the provided context, '):
result_text = result_text[31:].strip()
elif result_text.startswith('According to the provided text, '):
result_text = result_text[34:].strip()
elif result_text.startswith('According to the context, '):
result_text = result_text[26:].strip()
# Ensure the first letter is uppercase
result_text = result_text[0].upper() + result_text[1:] if result_text else result_text
# Extract and format sources (if available)
sources = []
for doc in relevant_context:
source_path = doc.metadata.get('source', '')
formatted_source = source_path[122:-4] if source_path else "Unknown source"
sources.append(formatted_source)
# Remove duplicates and combine into a single string
unique_sources = list(set(sources))
source_list = ", ".join(unique_sources)
# # Combine response text with sources
# result_text += f"\n\n**Sources:** {source_list}" if source_list else "\n\n**Sources:** None"
# Update conversation history
st.session_state.conversation_history += f"user: {prompt_input}\nassistant: {result_text}\n"
return result_text
except Exception as e:
# Handle rate limit or other errors gracefully
if "rate_limit_exceeded" in str(e).lower():
return "⚠️ Rate limit exceeded. Please clear the chat history and try again."
else:
return f"❌ An error occurred: {str(e)}"
# Display chat messages
for message in st.session_state.messages:
with st.chat_message(message["role"]):
st.write(message["content"])
# User-provided prompt for input box
if prompt := st.chat_input(placeholder="Ask a question..."):
# Increment query counter
st.session_state.query_counter += 1
# Append user query to session state
st.session_state.messages.append({"role": "user", "content": prompt})
with st.chat_message("user"):
st.write(prompt)
# Generate and display placeholder for assistant response
with st.chat_message("assistant"):
message_placeholder = st.empty() # Placeholder for response while it's being generated
with st.spinner("Generating response..."):
# Use conversation history when generating response
response = generate_response(prompt)
message_placeholder.markdown(response) # Replace placeholder with actual response
st.session_state.messages.append({"role": "assistant", "content": response})
# Check if query counter has reached the limit
if st.session_state.query_counter >= 10:
st.sidebar.warning("Conversation context has been reset after 10 queries.")
st.session_state.query_counter = 0 # Reset the counter
st.session_state.conversation_history = "" # Clear conversation history for the LLM
# Clear chat history function
def clear_chat_history():
# Clear chat messages (reset the assistant greeting)
st.session_state.messages = [{"role": "assistant", "content": "How may I help you today?"}]
# Reinitialize the chain to clear any stored history (ensures it forgets previous user inputs)
st.session_state.chain = init_chain()
# Clear the query counter and conversation history
st.session_state.query_counter = 0
st.session_state.conversation_history = ""
st.sidebar.button('Clear Chat History', on_click=clear_chat_history) |