krinya commited on
Commit
abf1abb
Β·
1 Parent(s): a721ff8

Add quote file browser to Gradio interface

Browse files

Features added:
- New 'Generated Quotes' tab in the UI
- Real-time display of quote files with metadata (name, date, size)
- Quote content viewer to read generated quotes directly in the interface
- Automatic refresh of quote list when new quotes are generated
- File selection dropdown with content preview
- Enhanced chat function to notify users when quotes are generated
- Download instructions for users

This allows users to easily view and access generated quote files without leaving the Gradio interface.

src/sales_assistant/ui_dashboard/gradio_app.py CHANGED
@@ -7,6 +7,8 @@ import os
7
  import sys
8
  import gradio as gr
9
  from typing import List, Tuple, Dict
 
 
10
 
11
  # Add the src directory to the path
12
  sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../..'))
@@ -30,8 +32,45 @@ class SalesAssistantChat:
30
  self.checkpointer = None
31
  self.callback_manager = None
32
  self.thread_id = None
 
33
  self.initialize_agent()
34
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  def initialize_agent(self):
36
  """Initialize the agent runner."""
37
  try:
@@ -55,7 +94,7 @@ class SalesAssistantChat:
55
  print(f"❌ Failed to initialize sales assistant: {e}")
56
  self.compiled_graph = None
57
 
58
- def chat_function(self, message: str, history: List[Dict[str, str]]) -> Tuple[str, List[Dict[str, str]]]:
59
  """
60
  Process a chat message and return the response.
61
 
@@ -64,13 +103,13 @@ class SalesAssistantChat:
64
  history: Chat history as list of message dictionaries
65
 
66
  Returns:
67
- Tuple of (empty_string, updated_history)
68
  """
69
  if not self.compiled_graph:
70
  error_response = "❌ Sales Assistant is not properly initialized. Please check your environment configuration."
71
  history.append({"role": "user", "content": message})
72
  history.append({"role": "assistant", "content": error_response})
73
- return "", history
74
 
75
  try:
76
  # Run conversation turn
@@ -85,12 +124,17 @@ class SalesAssistantChat:
85
  history.append({"role": "user", "content": message})
86
  history.append({"role": "assistant", "content": response})
87
 
 
 
 
 
 
88
  except Exception as e:
89
  error_response = f"❌ Error processing your request: {str(e)}"
90
  history.append({"role": "user", "content": message})
91
  history.append({"role": "assistant", "content": error_response})
92
 
93
- return "", history
94
 
95
 
96
  def create_gradio_interface():
@@ -137,43 +181,87 @@ def create_gradio_interface():
137
  """
138
  )
139
 
140
- # Chat interface
141
- chatbot = gr.Chatbot(
142
- value=[],
143
- height=400,
144
- label="Sales Assistant Chat",
145
- show_label=True,
146
- avatar_images=(
147
- "https://ui-avatars.com/api/?name=User&background=7dafff&color=fff", # User avatar
148
- "https://ui-avatars.com/api/?name=Ai&background=ffd966&color=333" #Assistant avatar
149
- ),
150
- type="messages"
151
- )
152
-
153
- # Input components
154
- with gr.Row():
155
- msg_input = gr.Textbox(
156
- placeholder="Ask me about products, request a quote, or explore our database...",
157
- label="Your Message",
158
- scale=4,
159
- lines=1
160
- )
161
- send_btn = gr.Button("Send", variant="primary", scale=1)
162
-
163
- # Example queries
164
- with gr.Row():
165
- gr.Examples(
166
- examples=[
167
- "Can you give me a price for a Saber 4k+?",
168
- "I need a 55 col Samsung TV, what are my options?",
169
- "What are the current exchange rates?",
170
- "Give me the cheapest Samsung 75 inch TV",
171
- "What categores of Sasmsung products do you have?",
172
- "Can you look for a mount or stand for a QH55C Samsung TV?",
173
- ],
174
- inputs=msg_input,
175
- label="Example Questions"
176
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
 
178
  # Additional information
179
  with gr.Accordion("ℹ️ About This Assistant", open=False):
@@ -188,6 +276,8 @@ def create_gradio_interface():
188
 
189
  The assistant uses natural language processing to understand your requests
190
  and can perform complex database queries to provide accurate information.
 
 
191
  """
192
  )
193
 
@@ -195,17 +285,39 @@ def create_gradio_interface():
195
  def submit_message(message, history):
196
  return chat_assistant.chat_function(message, history)
197
 
 
 
 
 
 
 
 
 
 
 
 
198
  # Wire up the events
199
  msg_input.submit(
200
  submit_message,
201
  inputs=[msg_input, chatbot],
202
- outputs=[msg_input, chatbot]
203
  )
204
 
205
  send_btn.click(
206
  submit_message,
207
  inputs=[msg_input, chatbot],
208
- outputs=[msg_input, chatbot]
 
 
 
 
 
 
 
 
 
 
 
209
  )
210
 
211
  return interface
 
7
  import sys
8
  import gradio as gr
9
  from typing import List, Tuple, Dict
10
+ from datetime import datetime
11
+ import glob
12
 
13
  # Add the src directory to the path
14
  sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../..'))
 
32
  self.checkpointer = None
33
  self.callback_manager = None
34
  self.thread_id = None
35
+ self.quotes_dir = os.path.join(os.path.dirname(__file__), '../created_quotes')
36
  self.initialize_agent()
37
 
38
+ def get_quote_files(self) -> List[Tuple[str, str, str]]:
39
+ """Get list of quote files with metadata."""
40
+ quote_files = []
41
+ if os.path.exists(self.quotes_dir):
42
+ pattern = os.path.join(self.quotes_dir, "quote_*.md")
43
+ files = glob.glob(pattern)
44
+ files.sort(key=os.path.getmtime, reverse=True) # Sort by modification time, newest first
45
+
46
+ for file_path in files:
47
+ filename = os.path.basename(file_path)
48
+ # Extract date from filename or file stats
49
+ mod_time = os.path.getmtime(file_path)
50
+ mod_date = datetime.fromtimestamp(mod_time).strftime("%Y-%m-%d %H:%M")
51
+ file_size = os.path.getsize(file_path)
52
+ size_kb = f"{file_size / 1024:.1f} KB"
53
+
54
+ quote_files.append((filename, mod_date, size_kb))
55
+
56
+ return quote_files
57
+
58
+ def read_quote_file(self, filename: str) -> str:
59
+ """Read and return the content of a quote file."""
60
+ if not filename:
61
+ return "No file selected."
62
+
63
+ file_path = os.path.join(self.quotes_dir, filename)
64
+ if os.path.exists(file_path):
65
+ try:
66
+ with open(file_path, 'r', encoding='utf-8') as f:
67
+ content = f.read()
68
+ return content
69
+ except Exception as e:
70
+ return f"Error reading file: {str(e)}"
71
+ else:
72
+ return "File not found."
73
+
74
  def initialize_agent(self):
75
  """Initialize the agent runner."""
76
  try:
 
94
  print(f"❌ Failed to initialize sales assistant: {e}")
95
  self.compiled_graph = None
96
 
97
+ def chat_function(self, message: str, history: List[Dict[str, str]]) -> Tuple[str, List[Dict[str, str]], List[Tuple[str, str, str]]]:
98
  """
99
  Process a chat message and return the response.
100
 
 
103
  history: Chat history as list of message dictionaries
104
 
105
  Returns:
106
+ Tuple of (empty_string, updated_history, updated_quote_files)
107
  """
108
  if not self.compiled_graph:
109
  error_response = "❌ Sales Assistant is not properly initialized. Please check your environment configuration."
110
  history.append({"role": "user", "content": message})
111
  history.append({"role": "assistant", "content": error_response})
112
+ return "", history, self.get_quote_files()
113
 
114
  try:
115
  # Run conversation turn
 
124
  history.append({"role": "user", "content": message})
125
  history.append({"role": "assistant", "content": response})
126
 
127
+ # Check if a new quote was generated by looking for "Quote generated" or similar in response
128
+ if "quote" in response.lower() and ("generated" in response.lower() or "created" in response.lower()):
129
+ response += "\n\nπŸ“„ **Check the 'Generated Quotes' tab to view your quote file!**"
130
+ history[-1] = {"role": "assistant", "content": response}
131
+
132
  except Exception as e:
133
  error_response = f"❌ Error processing your request: {str(e)}"
134
  history.append({"role": "user", "content": message})
135
  history.append({"role": "assistant", "content": error_response})
136
 
137
+ return "", history, self.get_quote_files()
138
 
139
 
140
  def create_gradio_interface():
 
181
  """
182
  )
183
 
184
+ # Create tabs for better organization
185
+ with gr.Tabs():
186
+ # Main Chat Tab
187
+ with gr.TabItem("πŸ’¬ Chat Assistant", id="chat_tab"):
188
+ # Chat interface
189
+ chatbot = gr.Chatbot(
190
+ value=[],
191
+ height=400,
192
+ label="Sales Assistant Chat",
193
+ show_label=True,
194
+ avatar_images=(
195
+ "https://ui-avatars.com/api/?name=User&background=7dafff&color=fff", # User avatar
196
+ "https://ui-avatars.com/api/?name=Ai&background=ffd966&color=333" #Assistant avatar
197
+ ),
198
+ type="messages"
199
+ )
200
+
201
+ # Input components
202
+ with gr.Row():
203
+ msg_input = gr.Textbox(
204
+ placeholder="Ask me about products, request a quote, or explore our database...",
205
+ label="Your Message",
206
+ scale=4,
207
+ lines=1
208
+ )
209
+ send_btn = gr.Button("Send", variant="primary", scale=1)
210
+
211
+ # Example queries
212
+ with gr.Row():
213
+ gr.Examples(
214
+ examples=[
215
+ "Can you give me a price for a Saber 4k+?",
216
+ "I need a 55 col Samsung TV, what are my options?",
217
+ "What are the current exchange rates?",
218
+ "Give me the cheapest Samsung 75 inch TV",
219
+ "What categores of Sasmsung products do you have?",
220
+ "Can you look for a mount or stand for a QH55C Samsung TV?",
221
+ ],
222
+ inputs=msg_input,
223
+ label="Example Questions"
224
+ )
225
+
226
+ # Generated Quotes Tab
227
+ with gr.TabItem("πŸ“„ Generated Quotes", id="quotes_tab"):
228
+ gr.Markdown("### Recently Generated Quote Files")
229
+
230
+ with gr.Row():
231
+ with gr.Column(scale=1):
232
+ quote_files_display = gr.Dataframe(
233
+ headers=["File Name", "Modified", "Size"],
234
+ datatype=["str", "str", "str"],
235
+ value=chat_assistant.get_quote_files(),
236
+ label="Quote Files",
237
+ interactive=False
238
+ )
239
+
240
+ refresh_btn = gr.Button("πŸ”„ Refresh Files", variant="secondary")
241
+
242
+ # File selection
243
+ file_dropdown = gr.Dropdown(
244
+ choices=[f[0] for f in chat_assistant.get_quote_files()],
245
+ label="Select Quote to View",
246
+ value=None
247
+ )
248
+
249
+ with gr.Column(scale=2):
250
+ quote_content = gr.Markdown(
251
+ value="Select a quote file to view its content.",
252
+ label="Quote Content"
253
+ )
254
+
255
+ download_info = gr.Markdown(
256
+ """
257
+ πŸ’‘ **How to download quotes:**
258
+ 1. Select a quote file from the dropdown
259
+ 2. Copy the content from the viewer
260
+ 3. Save it as a `.md` file on your computer
261
+
262
+ Or access the files directly in the `/created_quotes` folder.
263
+ """
264
+ )
265
 
266
  # Additional information
267
  with gr.Accordion("ℹ️ About This Assistant", open=False):
 
276
 
277
  The assistant uses natural language processing to understand your requests
278
  and can perform complex database queries to provide accurate information.
279
+
280
+ **Generated quotes are automatically saved and can be viewed in the 'Generated Quotes' tab.**
281
  """
282
  )
283
 
 
285
  def submit_message(message, history):
286
  return chat_assistant.chat_function(message, history)
287
 
288
+ def refresh_files():
289
+ files = chat_assistant.get_quote_files()
290
+ choices = [f[0] for f in files]
291
+ return files, gr.Dropdown(choices=choices, value=None)
292
+
293
+ def display_quote_content(filename):
294
+ if filename:
295
+ content = chat_assistant.read_quote_file(filename)
296
+ return content
297
+ return "Select a quote file to view its content."
298
+
299
  # Wire up the events
300
  msg_input.submit(
301
  submit_message,
302
  inputs=[msg_input, chatbot],
303
+ outputs=[msg_input, chatbot, quote_files_display]
304
  )
305
 
306
  send_btn.click(
307
  submit_message,
308
  inputs=[msg_input, chatbot],
309
+ outputs=[msg_input, chatbot, quote_files_display]
310
+ )
311
+
312
+ refresh_btn.click(
313
+ refresh_files,
314
+ outputs=[quote_files_display, file_dropdown]
315
+ )
316
+
317
+ file_dropdown.change(
318
+ display_quote_content,
319
+ inputs=[file_dropdown],
320
+ outputs=[quote_content]
321
  )
322
 
323
  return interface