vinhnx90 commited on
Commit
9b3a016
β€’
1 Parent(s): 9e53bcd

Refactor app using RunnableWithMessageHistory with better Prompt tuning

Browse files
Files changed (2) hide show
  1. app.py +48 -88
  2. chat_profile.py +2 -22
app.py CHANGED
@@ -1,22 +1,21 @@
1
  import os
2
  import streamlit as st
3
 
4
- from token_stream_handler import StreamHandler
5
- from chat_profile import User, Assistant, ChatProfileRoleEnum
6
-
7
- from langchain.chains import ConversationalRetrievalChain
8
  from langchain.text_splitter import RecursiveCharacterTextSplitter
9
  from langchain_community.document_loaders import Docx2txtLoader, PyPDFLoader, TextLoader
10
  from langchain_community.vectorstores.chroma import Chroma
11
  from langchain_openai import ChatOpenAI, OpenAIEmbeddings
 
 
 
12
 
13
- __import__("pysqlite3")
14
- import sys
15
-
16
- sys.modules["sqlite3"] = sys.modules.pop("pysqlite3")
17
-
18
  st.set_page_config(page_title="InkChatGPT", page_icon="πŸ“š")
19
 
 
 
 
20
 
21
  def load_and_process_file(file_data):
22
  """
@@ -52,20 +51,6 @@ def load_and_process_file(file_data):
52
  return vector_store
53
 
54
 
55
- def initialize_chat_model(vector_store):
56
- """
57
- Initialize the chat model with the given vector store.
58
- Returns a ConversationalRetrievalChain instance.
59
- """
60
- llm = ChatOpenAI(
61
- model="gpt-3.5-turbo",
62
- temperature=0,
63
- openai_api_key=st.secrets.OPENAI_API_KEY,
64
- )
65
- retriever = vector_store.as_retriever()
66
- return ConversationalRetrievalChain.from_llm(llm, retriever)
67
-
68
-
69
  def main():
70
  """
71
  The main function that runs the Streamlit app.
@@ -80,78 +65,51 @@ def main():
80
  if not st.secrets.OPENAI_API_KEY:
81
  st.info("Please add your OpenAI API key to continue.")
82
 
83
- assistant_message = """
84
- Hello, you can upload a document and chat with me to ask questions related to its content.
 
 
85
 
86
- Start by adding OpenAI API Key in the sidebar.
87
- """
88
- st.session_state["messages"] = [
89
- Assistant(message=assistant_message).build_message()
90
- ]
91
 
92
- if prompt := st.chat_input(
 
 
 
 
 
93
  placeholder="Chat with your document",
94
  disabled=(not openai_api_key),
95
  ):
96
- st.session_state.messages.append(User(message=prompt).build_message())
97
- st.chat_message(ChatProfileRoleEnum.User).write(prompt)
98
-
99
- handle_question(prompt)
100
-
101
-
102
- def handle_question(question):
103
- """
104
- Handles the user's question by generating a response and updating the chat history.
105
- """
106
- crc = st.session_state.crc
107
-
108
- if "history" not in st.session_state:
109
- st.session_state["history"] = []
110
-
111
- response = crc.run(
112
- {
113
- "question": question,
114
- "chat_history": st.session_state["history"],
115
- }
116
- )
117
-
118
- st.session_state["history"].append((question, response))
119
-
120
- for msg in st.session_state.messages:
121
- st.chat_message(msg.role).write(msg.content)
122
 
123
- with st.chat_message(ChatProfileRoleEnum.Assistant):
124
- stream_handler = StreamHandler(st.empty())
125
  llm = ChatOpenAI(
126
  openai_api_key=st.secrets.OPENAI_API_KEY,
127
- streaming=True,
128
- callbacks=[stream_handler],
129
  )
130
- response = llm.invoke(st.session_state.messages)
131
- st.session_state.messages.append(
132
- Assistant(message=response.content).build_message()
133
- )
134
-
135
-
136
- def display_chat_history():
137
- """
138
- Displays the chat history in the Streamlit app.
139
- """
140
-
141
- if "history" in st.session_state:
142
- st.markdown("## Chat History")
143
- for q, a in st.session_state["history"]:
144
- st.markdown(f"**Question:** {q}")
145
- st.write(a)
146
- st.write("---")
147
 
 
 
 
 
 
 
 
148
 
149
- def clear_history():
150
- """
151
- Clear the chat history stored in the session state.
152
- """
153
- if "history" in st.session_state:
154
- del st.session_state["history"]
155
 
156
 
157
  def build_sidebar():
@@ -170,10 +128,12 @@ def build_sidebar():
170
  vector_store = load_and_process_file(uploaded_file)
171
 
172
  if vector_store:
173
- crc = initialize_chat_model(vector_store)
174
- st.session_state.crc = crc
175
- st.chat_message(ChatProfileRoleEnum.Assistant).write(
176
- f"File: `{uploaded_file.name}`, processed successfully!"
 
 
177
  )
178
 
179
 
 
1
  import os
2
  import streamlit as st
3
 
4
+ from chat_profile import ChatProfileRoleEnum
 
 
 
5
  from langchain.text_splitter import RecursiveCharacterTextSplitter
6
  from langchain_community.document_loaders import Docx2txtLoader, PyPDFLoader, TextLoader
7
  from langchain_community.vectorstores.chroma import Chroma
8
  from langchain_openai import ChatOpenAI, OpenAIEmbeddings
9
+ from langchain_community.chat_message_histories import StreamlitChatMessageHistory
10
+ from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
11
+ from langchain_core.runnables.history import RunnableWithMessageHistory
12
 
13
+ # config page
 
 
 
 
14
  st.set_page_config(page_title="InkChatGPT", page_icon="πŸ“š")
15
 
16
+ # Set up memory
17
+ msgs = StreamlitChatMessageHistory(key="langchain_messages")
18
+
19
 
20
  def load_and_process_file(file_data):
21
  """
 
51
  return vector_store
52
 
53
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  def main():
55
  """
56
  The main function that runs the Streamlit app.
 
65
  if not st.secrets.OPENAI_API_KEY:
66
  st.info("Please add your OpenAI API key to continue.")
67
 
68
+ if len(msgs.messages) == 0:
69
+ msgs.add_ai_message(
70
+ """
71
+ Hello, how can I help you?
72
 
73
+ You can upload a document and chat with me to ask questions related to its content.
74
+ """
75
+ )
 
 
76
 
77
+ # Render current messages from StreamlitChatMessageHistory
78
+ for msg in msgs.messages:
79
+ st.chat_message(msg.type).write(msg.content)
80
+
81
+ # If user inputs a new prompt, generate and draw a new response
82
+ if question := st.chat_input(
83
  placeholder="Chat with your document",
84
  disabled=(not openai_api_key),
85
  ):
86
+ st.chat_message(ChatProfileRoleEnum.Human).write(question)
87
+ prompt = ChatPromptTemplate.from_messages(
88
+ [
89
+ ("system", "You are an AI chatbot having a conversation with a human."),
90
+ MessagesPlaceholder(variable_name="history"),
91
+ (ChatProfileRoleEnum.Human, f"{question}"),
92
+ ]
93
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
 
 
 
95
  llm = ChatOpenAI(
96
  openai_api_key=st.secrets.OPENAI_API_KEY,
97
+ temperature=0.0,
98
+ model_name="gpt-3.5-turbo",
99
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
 
101
+ chain = prompt | llm
102
+ chain_with_history = RunnableWithMessageHistory(
103
+ chain,
104
+ lambda session_id: msgs,
105
+ input_messages_key="question",
106
+ history_messages_key="history",
107
+ )
108
 
109
+ # Note: new messages are saved to history automatically by Langchain during run
110
+ config = {"configurable": {"session_id": "any"}}
111
+ response = chain_with_history.invoke({"question": question}, config)
112
+ st.chat_message(ChatProfileRoleEnum.AI).write(response.content)
 
 
113
 
114
 
115
  def build_sidebar():
 
128
  vector_store = load_and_process_file(uploaded_file)
129
 
130
  if vector_store:
131
+ msgs.add_ai_message(
132
+ f"""
133
+ File: `{uploaded_file.name}`, processed successfully!
134
+
135
+ Feel free to ask me any question.
136
+ """
137
  )
138
 
139
 
chat_profile.py CHANGED
@@ -1,26 +1,6 @@
1
- from langchain.schema import ChatMessage
2
  from enum import Enum
3
 
4
 
5
  class ChatProfileRoleEnum(str, Enum):
6
- User = "user"
7
- Assistant = "assistant"
8
-
9
-
10
- class ChatProfile:
11
- def __init__(self, role: str, message: str):
12
- self.role = role
13
- self.message = message
14
-
15
- def build_message(self) -> ChatMessage:
16
- return ChatMessage(role=self.role, content=self.message)
17
-
18
-
19
- class Assistant(ChatProfile):
20
- def __init__(self, message: str):
21
- super().__init__(ChatProfileRoleEnum.Assistant, message)
22
-
23
-
24
- class User(ChatProfile):
25
- def __init__(self, message: str):
26
- super().__init__(ChatProfileRoleEnum.User, message)
 
 
1
  from enum import Enum
2
 
3
 
4
  class ChatProfileRoleEnum(str, Enum):
5
+ Human = "human"
6
+ AI = "ai"