Aniq-63 commited on
Commit
9d537cc
·
verified ·
1 Parent(s): 5e67bfb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +151 -164
app.py CHANGED
@@ -12,47 +12,81 @@ from langchain.tools import Tool
12
  from langchain.agents import AgentExecutor, create_tool_calling_agent
13
  from langchain_core.messages import HumanMessage, AIMessage
14
 
 
15
  # --- Database Setup ---
 
 
16
  @st.cache_resource
17
  def init_db():
18
  conn = sqlite3.connect('users.db', check_same_thread=False)
19
  c = conn.cursor()
20
-
21
- # Users table
22
  c.execute('''CREATE TABLE IF NOT EXISTS users
23
  (id INTEGER PRIMARY KEY AUTOINCREMENT,
24
  username TEXT UNIQUE NOT NULL,
25
  password TEXT NOT NULL,
26
  previous_chat_history TEXT,
27
  previous_products_bought TEXT)''')
28
-
29
- # Company settings table
30
- c.execute('''CREATE TABLE IF NOT EXISTS company_settings
31
- (id INTEGER PRIMARY KEY AUTOINCREMENT,
32
- company_name TEXT,
33
- company_business TEXT,
34
- agent_name TEXT,
35
- key_features TEXT)''')
36
-
37
- # Insert default settings if empty
38
- c.execute('SELECT COUNT(*) FROM company_settings')
39
- if c.fetchone()[0] == 0:
40
- c.execute('''INSERT INTO company_settings
41
- (company_name, company_business, agent_name, key_features)
42
- VALUES (?, ?, ?, ?)''',
43
- ("TechElectronics",
44
- "Consumer Electronics Retailer",
45
- "Alex",
46
- "Cutting-edge technology, Competitive pricing, Excellent customer service"))
47
  conn.commit()
48
  return conn
49
 
50
  conn = init_db()
51
 
 
52
  class User:
53
- # ... (existing User class remains unchanged) ...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
 
55
  # --- AI Agent Setup ---
 
56
  os.environ["GROQ_API_KEY"] = st.secrets["GROQ_API_KEY"]
57
  llm = ChatGroq(
58
  temperature=0.1,
@@ -60,10 +94,12 @@ llm = ChatGroq(
60
  api_key=st.secrets["GROQ_API_KEY"],
61
  )
62
 
 
63
  embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
64
 
 
65
  @st.cache_resource
66
- def load_data(data_version):
67
  loader = CSVLoader(file_path="electronics_products.csv")
68
  docs = loader.load()
69
  text_splitter = RecursiveCharacterTextSplitter(chunk_size=100, chunk_overlap=20)
@@ -71,86 +107,88 @@ def load_data(data_version):
71
  vectorstore = InMemoryVectorStore.from_documents(documents=splits, embedding=embeddings)
72
  return vectorstore.as_retriever()
73
 
74
- # Initialize with default data version
75
- retriever = load_data(0)
76
 
77
- def get_company_settings():
78
- conn = sqlite3.connect('users.db')
79
- c = conn.cursor()
80
- c.execute('SELECT * FROM company_settings WHERE id=1')
81
- settings = c.fetchone()
82
- conn.close()
83
- return {
84
- 'company_name': settings[1],
85
- 'company_business': settings[2],
86
- 'agent_name': settings[3],
87
- 'key_features': settings[4]
88
- }
89
 
90
- # --- Admin Dashboard ---
91
- def admin_dashboard():
92
- st.header("Admin Dashboard")
93
-
94
- # Company Settings Form
95
- with st.expander("Company Settings"):
96
- settings = get_company_settings()
97
-
98
- with st.form("company_settings"):
99
- new_name = st.text_input("Company Name", value=settings['company_name'])
100
- new_business = st.text_input("Business", value=settings['company_business'])
101
- new_agent = st.text_input("Agent Name", value=settings['agent_name'])
102
- new_features = st.text_area("Key Features", value=settings['key_features'])
103
-
104
- if st.form_submit_button("Save Settings"):
105
- conn = sqlite3.connect('users.db')
106
- c = conn.cursor()
107
- c.execute('''UPDATE company_settings SET
108
- company_name=?, company_business=?, agent_name=?, key_features=?
109
- WHERE id=1''',
110
- (new_name, new_business, new_agent, new_features))
111
- conn.commit()
112
- conn.close()
113
- st.success("Settings updated!")
114
 
115
- # Product Management
116
- with st.expander("Product Management"):
117
- st.subheader("Update Product Catalog")
118
- uploaded_file = st.file_uploader("Upload new CSV", type="csv")
119
-
120
- if uploaded_file is not None:
121
- # Save the uploaded file
122
- with open("electronics_products.csv", "wb") as f:
123
- f.write(uploaded_file.getbuffer())
124
- # Update data version to refresh cache
125
- st.session_state.data_version = st.session_state.get("data_version", 0) + 1
126
- st.success("Product catalog updated!")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
 
128
- if st.button("Back to Main"):
129
- st.session_state.show_admin = False
130
- st.rerun()
131
 
132
  # --- Streamlit UI ---
133
  def main():
134
- st.set_page_config(page_title="AI Sales Assistant", layout="wide")
135
 
136
- # Initialize session states
137
  if 'user' not in st.session_state:
138
  st.session_state.user = None
139
  st.session_state.chat_history = []
140
- if 'show_admin' not in st.session_state:
141
- st.session_state.show_admin = False
142
- if 'data_version' not in st.session_state:
143
- st.session_state.data_version = 0
144
-
145
- # Check admin status first
146
- if st.session_state.show_admin:
147
- admin_dashboard()
148
- return
149
-
150
  # Authentication
151
  if not st.session_state.user:
152
  st.header("Login/Register")
153
- tab1, tab2, tab3 = st.tabs(["Login", "Register", "Admin"])
154
 
155
  with tab1:
156
  with st.form("Login"):
@@ -159,6 +197,7 @@ def main():
159
  if st.form_submit_button("Login"):
160
  user = User.get_by_username(username)
161
  if user and check_password_hash(user.password, password):
 
162
  st.session_state.user = user
163
  st.session_state.chat_history = user.chat_history
164
  st.rerun()
@@ -177,101 +216,49 @@ def main():
177
  st.session_state.user = user
178
  st.session_state.chat_history = []
179
  st.rerun()
180
-
181
- with tab3:
182
- with st.form("Admin Login"):
183
- admin_key = st.text_input("Admin Key", type="password")
184
- if st.form_submit_button("Enter Admin Dashboard"):
185
- if admin_key == st.secrets.get("ADMIN_KEY", "default_admin_key"):
186
- st.session_state.show_admin = True
187
- st.rerun()
188
- else:
189
- st.error("Invalid Admin Key")
190
 
191
  else:
192
- # Main Chat Interface
193
- settings = get_company_settings()
194
- st.title(f"{settings['company_name']} AI Sales Assistant 🤖")
195
 
196
- st.header(f"Welcome to {settings['company_name']}, {st.session_state.user.username} 😊!")
197
-
198
- # Reload data with current version
199
- global retriever
200
- retriever = load_data(st.session_state.data_version)
201
-
202
- # Dynamic system prompt
203
- system_prompt = f"""
204
- You are {settings['agent_name']}, the AI Sales Assistant for {settings['company_name']} ({settings['company_business']}).
205
-
206
- Company Profile:
207
- - Company Name: {settings['company_name']}
208
- - Business: {settings['company_business']}
209
- - Key Features: {settings['key_features']}
210
-
211
- Product Availability:
212
- - Only recommend and discuss products listed in the provided document.
213
- - Do not suggest unavailable or out-of-stock products.
214
- - Always verify product availability before making recommendations.
215
-
216
- Conversation Flow:
217
- 1. Introduction
218
- 2. Qualification
219
- 3. Understanding Needs
220
- 4. Needs Analysis
221
- 5. Solution Presentation (Only recommend available products)
222
- 6. Confirmation
223
- 7. If the prospect agrees to purchase, thank them and provide the payment link: https://www.example.com/payment
224
 
225
- Guidelines:
226
- - Maintain natural, professional conversations
227
- - Follow company policies
228
- - Be helpful and polite
229
- - Always cross-check product recommendations with the available inventory in the CSV document
230
- """
231
-
232
- # Agent setup with dynamic prompt
233
- prompt = ChatPromptTemplate.from_messages([
234
- ("system", system_prompt),
235
- MessagesPlaceholder(variable_name="chat_history"),
236
- ("human", "{input}"),
237
- MessagesPlaceholder(variable_name="agent_scratchpad")
238
- ])
239
-
240
- tool = Tool(
241
- name="retriever",
242
- func=lambda q: retriever.get_relevant_documents(q),
243
- description="Useful for retrieving product information"
244
- )
245
-
246
- agent = create_tool_calling_agent(llm, [tool], prompt)
247
- agent_executor = AgentExecutor(agent=agent, tools=[tool], verbose=True)
248
-
249
- # Chat handling
250
- if prompt_input := st.chat_input("Type your message here..."):
251
- # Add user message
252
  with st.chat_message("user"):
253
- st.write(prompt_input)
254
 
255
  # Get AI response
256
  with st.chat_message("assistant"):
257
  response = agent_executor.invoke({
258
- "input": prompt_input,
259
  "chat_history": [HumanMessage(content=msg["content"]) if msg["type"] == "human" else AIMessage(content=msg["content"])
260
  for msg in st.session_state.chat_history]
261
  })["output"]
262
  st.write(response)
263
 
 
264
  if "https://www.example.com/payment" in response:
265
  st.session_state.user.update_products_bought(["Latest Product"])
266
- st.success("Product added to your purchases!")
267
-
268
- # Update chat history
269
  new_messages = [
270
- {"type": "human", "content": prompt_input},
271
  {"type": "ai", "content": response}
272
  ]
 
 
273
  st.session_state.user.update_chat_history(new_messages)
274
  st.session_state.chat_history += new_messages
275
 
276
  if __name__ == "__main__":
277
- main()
 
12
  from langchain.agents import AgentExecutor, create_tool_calling_agent
13
  from langchain_core.messages import HumanMessage, AIMessage
14
 
15
+
16
  # --- Database Setup ---
17
+
18
+ # Database initialization with caching
19
  @st.cache_resource
20
  def init_db():
21
  conn = sqlite3.connect('users.db', check_same_thread=False)
22
  c = conn.cursor()
 
 
23
  c.execute('''CREATE TABLE IF NOT EXISTS users
24
  (id INTEGER PRIMARY KEY AUTOINCREMENT,
25
  username TEXT UNIQUE NOT NULL,
26
  password TEXT NOT NULL,
27
  previous_chat_history TEXT,
28
  previous_products_bought TEXT)''')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  conn.commit()
30
  return conn
31
 
32
  conn = init_db()
33
 
34
+
35
  class User:
36
+ def __init__(self, id, username, password, chat_history = None, products_bought = None):
37
+ self.id = id
38
+ self.username = username
39
+ self.password = password
40
+ self.chat_history = chat_history or []
41
+ self.products_bought = products_bought or []
42
+
43
+ # To register a new user
44
+ @classmethod
45
+ def create(cls, username, password):
46
+ hashed_pw = generate_password_hash(password)
47
+ conn = sqlite3.connect('users.db')
48
+ c = conn.cursor()
49
+ c.execute('INSERT INTO users (username, password) VALUES (?, ?)',(username, hashed_pw))
50
+ user_id = c.lastrowid
51
+ conn.commit()
52
+ conn.close()
53
+ return cls(user_id, username, hashed_pw)
54
+
55
+ # To retrieve an existing user from the database by username.
56
+ @classmethod
57
+ def get_by_username(cls, username):
58
+ conn = sqlite3.connect('users.db')
59
+ c = conn.cursor()
60
+ c.execute('SELECT * FROM users WHERE username = ?', (username,))
61
+ user = c.fetchone()
62
+ conn.close()
63
+ if user:
64
+ return cls(user[0], user[1], user[2],
65
+ eval(user[3]) if user[3] else [],
66
+ eval(user[4]) if user[4] else [])
67
+ return None
68
+
69
+ def update_chat_history(self, new_messages):
70
+ conn = sqlite3.connect('users.db')
71
+ c = conn.cursor()
72
+ updated_history = self.chat_history + new_messages
73
+ c.execute('UPDATE users SET previous_chat_history = ? WHERE id = ?',
74
+ (str(updated_history), self.id))
75
+ conn.commit()
76
+ conn.close()
77
+
78
+ def update_products_bought(self, new_products):
79
+ conn = sqlite3.connect('users.db')
80
+ c = conn.cursor()
81
+ updated_products = self.products_bought + new_products
82
+ c.execute('UPDATE users SET previous_products_bought = ? WHERE id = ?',
83
+ (str(updated_products), self.id))
84
+ conn.commit()
85
+ conn.close()
86
+
87
 
88
  # --- AI Agent Setup ---
89
+ # Load the LLM model from Groq
90
  os.environ["GROQ_API_KEY"] = st.secrets["GROQ_API_KEY"]
91
  llm = ChatGroq(
92
  temperature=0.1,
 
94
  api_key=st.secrets["GROQ_API_KEY"],
95
  )
96
 
97
+ # Load the HuggingFace Embeddings
98
  embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
99
 
100
+ # Load and process CSV data
101
  @st.cache_resource
102
+ def load_data():
103
  loader = CSVLoader(file_path="electronics_products.csv")
104
  docs = loader.load()
105
  text_splitter = RecursiveCharacterTextSplitter(chunk_size=100, chunk_overlap=20)
 
107
  vectorstore = InMemoryVectorStore.from_documents(documents=splits, embedding=embeddings)
108
  return vectorstore.as_retriever()
109
 
110
+ retriever = load_data()
 
111
 
112
+ def retrieve_query(query: str):
113
+ """Retrieves documents related to the query."""
114
+ return retriever.get_relevant_documents(query)
 
 
 
 
 
 
 
 
 
115
 
116
+ tool = Tool(
117
+ name="retriever",
118
+ func=retrieve_query,
119
+ description="Useful for retrieving product information"
120
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
 
122
+ # Agent setup
123
+ # System prompt template
124
+ system_prompt = """
125
+ You are {agent_name}, the AI Sales Assistant for {company_name} ({company_business}).
126
+
127
+ Company Profile:
128
+ - Company Name: {company_name}
129
+ - Business: {company_business}
130
+ - Key Features: {key_features}
131
+
132
+ Product Availability:
133
+ - Only recommend and discuss products listed in the provided in document.
134
+ - Do not suggest unavailable or out-of-stock products.
135
+ - Always verify product availability before making recommendations.
136
+
137
+ Conversation Flow:
138
+ 1. Introduction
139
+ 2. Qualification
140
+ 3. Understanding Needs
141
+ 4. Needs Analysis
142
+ 5. Solution Presentation (Only recommend available products)
143
+ 6. Confirmation
144
+ 7. If the prospect agrees to purchase, thank them and provide the payment link: https://www.example.com/payment
145
+
146
+ Guidelines:
147
+ - Maintain natural, professional conversations
148
+ - Follow company policies
149
+ - Be helpful and polite
150
+ - Always cross-check product recommendations with the available inventory in the CSV document
151
+ """
152
+
153
+ # Define the company and agent details
154
+ company_name = "TechElectronics"
155
+ company_business = "Consumer Electronics Retailer"
156
+ agent_name = "Alex"
157
+ key_features = "Cutting-edge technology, Competitive pricing, Excellent customer service"
158
+
159
+ # Format the system prompt with the company and agent details
160
+ formatted_system_prompt = system_prompt.format(
161
+ agent_name=agent_name,
162
+ company_name=company_name,
163
+ company_business=company_business,
164
+ key_features=key_features
165
+ )
166
+
167
+ prompt = ChatPromptTemplate.from_messages([
168
+ ("system", formatted_system_prompt),
169
+ MessagesPlaceholder(variable_name="chat_history"),
170
+ ("human", "{input}"),
171
+ MessagesPlaceholder(variable_name="agent_scratchpad")
172
+ ])
173
+
174
+ tools = [tool]
175
+ agent = create_tool_calling_agent(llm, tools, prompt)
176
+ agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
177
 
 
 
 
178
 
179
  # --- Streamlit UI ---
180
  def main():
181
+ st.title(f"{company_name} AI Sales Assistant 🤖")
182
 
183
+ # Initialize session state
184
  if 'user' not in st.session_state:
185
  st.session_state.user = None
186
  st.session_state.chat_history = []
187
+
 
 
 
 
 
 
 
 
 
188
  # Authentication
189
  if not st.session_state.user:
190
  st.header("Login/Register")
191
+ tab1, tab2 = st.tabs(["Login", "Register"])
192
 
193
  with tab1:
194
  with st.form("Login"):
 
197
  if st.form_submit_button("Login"):
198
  user = User.get_by_username(username)
199
  if user and check_password_hash(user.password, password):
200
+ # If valid, the user is stored in st.session_state.user and their chat history is loaded.
201
  st.session_state.user = user
202
  st.session_state.chat_history = user.chat_history
203
  st.rerun()
 
216
  st.session_state.user = user
217
  st.session_state.chat_history = []
218
  st.rerun()
 
 
 
 
 
 
 
 
 
 
219
 
220
  else:
221
+ # Chat Interface
222
+ st.header(f"Welcome to {company_name}, {st.session_state.user.username}😊!")
223
+ st.subheader("Chat with our AI Sales Assistant")
224
 
225
+ # # Display chat history
226
+ # for msg in st.session_state.chat_history:
227
+ # if msg["type"] == "human":
228
+ # with st.chat_message("user"):
229
+ # st.write(msg["content"])
230
+ # else:
231
+ # with st.chat_message("assistant"):
232
+ # st.write(msg["content"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
 
234
+ if prompt := st.chat_input("Type you Message here..."):
235
+ #Add user message to chat
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
236
  with st.chat_message("user"):
237
+ st.write(prompt)
238
 
239
  # Get AI response
240
  with st.chat_message("assistant"):
241
  response = agent_executor.invoke({
242
+ "input": prompt,
243
  "chat_history": [HumanMessage(content=msg["content"]) if msg["type"] == "human" else AIMessage(content=msg["content"])
244
  for msg in st.session_state.chat_history]
245
  })["output"]
246
  st.write(response)
247
 
248
+ # Check if payment link is provided
249
  if "https://www.example.com/payment" in response:
250
  st.session_state.user.update_products_bought(["Latest Product"])
251
+ st.success("Product added to your purchases!")
252
+
253
+ # Update chat history in database
254
  new_messages = [
255
+ {"type": "human", "content": prompt},
256
  {"type": "ai", "content": response}
257
  ]
258
+ # Both the user’s message and the assistant’s reply are appended to the persistent chat history
259
+ # (both in session and in the database), ensuring conversation continuity.
260
  st.session_state.user.update_chat_history(new_messages)
261
  st.session_state.chat_history += new_messages
262
 
263
  if __name__ == "__main__":
264
+ main()