aminaj commited on
Commit
0dca065
·
verified ·
1 Parent(s): baf7278

Upload chat_interface.py

Browse files
Files changed (1) hide show
  1. frontend/chat_interface.py +148 -0
frontend/chat_interface.py ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from backend.analysis import llm
3
+ from langchain.chains import create_history_aware_retriever, create_retrieval_chain
4
+ from langchain.chains.combine_documents import create_stuff_documents_chain
5
+ from langchain_community.chat_message_histories import ChatMessageHistory
6
+ from langchain_core.chat_history import BaseChatMessageHistory
7
+ from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
8
+ from langchain_core.runnables.history import RunnableWithMessageHistory
9
+
10
+ # Chat interface section of the application - displayed at the right
11
+ def render_chat_interface():
12
+ st.header("Chat with the Resume") # Header for the chat interface
13
+
14
+ # Add CSS for fixing chat input position at the bottom
15
+ st.markdown("""
16
+ <style>
17
+ .stChatInput {
18
+ position: fixed;
19
+ bottom: 0;
20
+ right: 0;
21
+ width: 40%;
22
+ padding: 1rem;
23
+ background-color: white;
24
+ z-index: 1000;
25
+ }
26
+ .stChatFloatingInputContainer {
27
+ margin-bottom: 20px;
28
+ }
29
+ </style>
30
+ """, unsafe_allow_html=True) # Injecting custom CSS for styling
31
+
32
+ # Initialize empty chat messages
33
+ if "messages" not in st.session_state:
34
+ st.session_state.messages = [] # Initialize messages in session state
35
+
36
+ # Check if the vector store is available
37
+ if "vector_store" in st.session_state:
38
+ # Setting up the vector store as retriever
39
+ retriever = st.session_state.vector_store.as_retriever(
40
+ search_type="mmr", # Uses Maximum Marginal Relevance for search
41
+ search_kwargs={
42
+ "k": 3, # Fetch top 3 chunks
43
+ }
44
+ )
45
+
46
+ # Chat logic setup for contextualizing user questions
47
+ contextualize_q_system_prompt = (
48
+ "Given a chat history and the latest user question "
49
+ "which might reference context in the chat history, "
50
+ "formulate a standalone question which can be understood "
51
+ "without the chat history. Do NOT answer the question, "
52
+ "just reformulate it if needed and otherwise return it as is."
53
+ )
54
+
55
+ # Creating a prompt template for contextualizing questions
56
+ contextualize_q_prompt = ChatPromptTemplate.from_messages([
57
+ ("system", contextualize_q_system_prompt),
58
+ MessagesPlaceholder("chat_history"),
59
+ ("human", "{input}"),
60
+ ])
61
+
62
+ # Creating a history-aware retriever with the language model
63
+ history_aware_retriever = create_history_aware_retriever(
64
+ llm, retriever, contextualize_q_prompt
65
+ )
66
+
67
+ # System prompt for answering questions
68
+ system_prompt = (
69
+ "You are an assistant for question-answering tasks. "
70
+ "Use the following pieces of retrieved context to answer "
71
+ "the question. If you don't know the answer, say that you "
72
+ "don't know. Use three sentences maximum and keep the "
73
+ "answer concise."
74
+ "\n\n"
75
+ "{context}"
76
+ )
77
+
78
+ # Creating a prompt template for question-answering
79
+ qa_prompt = ChatPromptTemplate.from_messages([
80
+ ("system", system_prompt),
81
+ MessagesPlaceholder("chat_history"),
82
+ ("human", "{input}"),
83
+ ])
84
+
85
+ # Setting up the question-answering chain
86
+ question_answer_chain = create_stuff_documents_chain(llm, qa_prompt)
87
+ retrieval_chain = create_retrieval_chain(history_aware_retriever, question_answer_chain)
88
+
89
+ # Chat history management using a dictionary
90
+ store = {}
91
+
92
+ def get_session_history(session_id: str) -> BaseChatMessageHistory:
93
+ if session_id not in store:
94
+ store[session_id] = ChatMessageHistory() # Create a new history if not exists
95
+ return store[session_id] # Return the chat history
96
+
97
+ # Creating a runnable chain with message history
98
+ conversational_retrieval_chain = RunnableWithMessageHistory(
99
+ retrieval_chain,
100
+ get_session_history,
101
+ input_messages_key="input",
102
+ history_messages_key="chat_history",
103
+ output_messages_key="answer",
104
+ )
105
+
106
+ # Create a container for messages with bottom padding for input space
107
+ chat_container = st.container()
108
+
109
+ # Add space at the bottom to prevent messages from being hidden behind input
110
+ st.markdown("<div style='height: 100px;'></div>", unsafe_allow_html=True)
111
+
112
+ # Input box - will be fixed at bottom due to CSS
113
+ prompt = st.chat_input("Ask about the resume") # Input for user queries
114
+
115
+ # Display messages in the container
116
+ with chat_container:
117
+ for message in st.session_state.messages: # Iterate through session messages
118
+ with st.chat_message(message["role"]):
119
+ st.markdown(message["content"]) # Display message content
120
+
121
+ if prompt: # Check if there is a user input
122
+ st.session_state.messages.append({"role": "user", "content": prompt}) # Store user message
123
+ with chat_container:
124
+ with st.chat_message("user"):
125
+ st.markdown(prompt) # Display user input
126
+
127
+ with st.chat_message("assistant"):
128
+ # Prepare input data for the conversational chain
129
+ input_data = {
130
+ "input": prompt,
131
+ "chat_history": st.session_state.messages,
132
+ }
133
+ response = conversational_retrieval_chain.invoke(
134
+ input_data,
135
+ config={
136
+ "configurable": {"session_id": "abc123"} # Setting session ID
137
+ },
138
+ )
139
+ answer_text = response['answer'] # Extract the assistant's response
140
+ st.markdown(answer_text) # Display the response
141
+
142
+ st.session_state.messages.append({"role": "assistant", "content": answer_text}) # Store assistant response
143
+
144
+ # Force a rerun to update the chat immediately
145
+ st.rerun() # Refresh the Streamlit app
146
+
147
+ else:
148
+ st.info("Please upload a resume and analyze it to start chatting.")