buianh0803 commited on
Commit
8c03b83
·
verified ·
1 Parent(s): 1d67488

Upload gradio_hf.py

Browse files
Files changed (1) hide show
  1. gradio_hf.py +457 -0
gradio_hf.py ADDED
@@ -0,0 +1,457 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import pandas as pd
3
+ import gradio as gr
4
+ import time
5
+ import re
6
+ import os
7
+ from dotenv import load_dotenv
8
+ load_dotenv()
9
+
10
+ API_BASE_URL = os.getenv("API_BASE_URL")
11
+
12
+
13
+ def clear_chat():
14
+ """Clear all conversation history and reset all states via API"""
15
+ try:
16
+ requests.post(f"{API_BASE_URL}/clear_memory",
17
+ json={"reset_cache": True, "reset_model": False})
18
+ except Exception as e:
19
+ print(f"Warning: clear_memory failed: {e}")
20
+
21
+ # Return empty values for all components that need to be reset
22
+ # chatbot, state, raw_documents, chatbot_state, textbox
23
+ return [], {}, {}, [], ""
24
+
25
+
26
+ def respond_to_chat(message, history, state, selected_model, debug_mode):
27
+ """Handle chat responses with image support"""
28
+ start = time.perf_counter()
29
+ # Handle multimodal input - message is a dict with 'text' and 'files' keys
30
+ if isinstance(message, dict):
31
+ text_message = message.get('text', '')
32
+ files = message.get('files', [])
33
+
34
+ # Process any uploaded images
35
+ image_path = None
36
+ if files:
37
+ image_path = files[0]
38
+ print(image_path)
39
+
40
+ user_query = text_message
41
+ else:
42
+ user_query = message
43
+ image_path = None
44
+
45
+ # call API
46
+ try:
47
+ if image_path:
48
+ with open(image_path, 'rb') as f:
49
+ files = {"image": f}
50
+ data = {"message": user_query, "debug": debug_mode}
51
+ resp = requests.post(
52
+ f"{API_BASE_URL}/chat_with_image", files=files, data=data, timeout=120)
53
+ else:
54
+ payload = {"message": user_query, "debug": debug_mode}
55
+ resp = requests.post(f"{API_BASE_URL}/chat",
56
+ json=payload, timeout=120)
57
+
58
+ if resp.status_code == 200:
59
+ j = resp.json()
60
+ response = j.get("response", "")
61
+ specs_advantages = j.get("specs_advantages")
62
+ raw_documents = j.get("raw_documents")
63
+ outputs = j.get("outputs")
64
+ else:
65
+ response = f"Error: API status {resp.status_code}"
66
+ specs_advantages, raw_documents, outputs = None, None, None
67
+ except Exception as e:
68
+ response = f"Error calling API: {e}"
69
+ specs_advantages, raw_documents, outputs = None, None, None
70
+
71
+ end = time.perf_counter()
72
+
73
+ if state is None:
74
+ state = {}
75
+
76
+ # specs_advantages is now always a dict for both products and solutions
77
+ if isinstance(specs_advantages, dict):
78
+ state["specs_advantages"] = specs_advantages
79
+ state["raw_documents"] = raw_documents
80
+ state["outputs"] = outputs
81
+
82
+ return response
83
+
84
+
85
+ def show_specs(state, history=None):
86
+ specs_map = state.get("specs_advantages", {})
87
+ columns = ["Thông số"]
88
+ raw_data = []
89
+ if history is None:
90
+ history = []
91
+
92
+ if not specs_map:
93
+ df = pd.DataFrame({}, columns=columns)
94
+ markdown_table = df.to_markdown(index=False)
95
+ # Fix: Use proper ChatInterface message format
96
+ history.append(
97
+ {"role": "assistant", "content": f"📄 Thông số kỹ thuật\n{markdown_table}"})
98
+ return history
99
+
100
+ # print(specs_map)
101
+ for prod_id, data in specs_map.items():
102
+ spec = data.get("specification", None)
103
+ model = data.get("model", "")
104
+ url = data.get("url", "")
105
+
106
+ # Handle both products and solution packages
107
+ if url:
108
+ full_name = f"**[{data['name']} {model}]({url})**"
109
+ else:
110
+ full_name = f"**[{data['name']} {model}]**"
111
+
112
+ if full_name not in columns:
113
+ columns.append(full_name)
114
+
115
+ if spec:
116
+ # Check if this is a solution package (contains markdown table)
117
+ if "### 📦" in spec:
118
+ # For solution packages, parse the markdown table properly
119
+ lines = spec.split('\n')
120
+ in_table = False
121
+ headers = []
122
+
123
+ for line in lines:
124
+ line = line.strip()
125
+ if '|' in line and '---' not in line and line.startswith('|') and line.endswith('|'):
126
+ cells = [cell.strip()
127
+ for cell in line.split('|')[1:-1]]
128
+
129
+ if not in_table:
130
+ # This is the header row
131
+ headers = cells
132
+ in_table = True
133
+ continue
134
+
135
+ # This is a data row
136
+ if len(cells) >= len(headers):
137
+ for i, header in enumerate(headers):
138
+ if i < len(cells):
139
+ param_name = header
140
+ param_value = cells[i]
141
+
142
+ existing_row = None
143
+ for row in raw_data:
144
+ if row["Thông số"] == param_name:
145
+ existing_row = row
146
+ break
147
+
148
+ if existing_row:
149
+ existing_row[full_name] = param_value
150
+ else:
151
+ new_row = {"Thông số": param_name}
152
+ for col in columns[1:]:
153
+ new_row[col] = ""
154
+ new_row[full_name] = param_value
155
+ raw_data.append(new_row)
156
+ elif in_table and (not line or not line.startswith('|')):
157
+ in_table = False
158
+ else:
159
+ # For products, parse specification items
160
+ items = re.split(r';|\n', spec)
161
+ for item in items:
162
+ if ":" in item:
163
+ key, value = item.split(':', 1)
164
+ spec_key = key.strip().capitalize()
165
+ if spec_key == "Vậtl iệu":
166
+ spec_key = "Vật liệu"
167
+
168
+ existing_row = None
169
+ for row in raw_data:
170
+ if row["Thông số"] == spec_key:
171
+ existing_row = row
172
+ break
173
+
174
+ if existing_row:
175
+ existing_row[full_name] = value.strip(
176
+ ) if value else ""
177
+ else:
178
+ new_row = {"Thông số": spec_key}
179
+ for col in columns[1:]:
180
+ new_row[col] = ""
181
+ new_row[full_name] = value.strip() if value else ""
182
+ raw_data.append(new_row)
183
+
184
+ if raw_data:
185
+ df = pd.DataFrame(raw_data, columns=columns)
186
+ df = df.fillna("").replace("None", "").replace("nan", "")
187
+ else:
188
+ df = pd.DataFrame(
189
+ [["Không có thông số kỹ thuật", "", ""]], columns=columns)
190
+
191
+ markdown_table = df.to_markdown(index=False)
192
+ # Fix: Use proper ChatInterface message format
193
+ history.append(
194
+ {"role": "assistant", "content": f"📄 Thông số kỹ thuật\n{markdown_table}"})
195
+ return history
196
+
197
+
198
+ def show_advantages(state, history=None):
199
+ specs_map = state.get("specs_advantages", {})
200
+ columns = ["Tên", "Ưu điểm nổi trội"]
201
+ table_data = []
202
+ if history is None:
203
+ history = []
204
+
205
+ if not specs_map:
206
+ df = pd.DataFrame([["Không có ưu điểm", ""]], columns=columns)
207
+ markdown_table = df.to_markdown(index=False)
208
+ # Fix: Use proper ChatInterface message format
209
+ history.append(
210
+ {"role": "assistant", "content": f"💡 Ưu điểm nổi trội\n{markdown_table}"})
211
+ return history
212
+
213
+ for prod_id, data in specs_map.items():
214
+ adv = data.get("advantages", "Không có ưu điểm")
215
+ model = data.get("model", "")
216
+ url = data.get("url", "")
217
+
218
+ # Handle both products and solution packages
219
+ if url:
220
+ full_name = f"**[{data['name']} {model}]({url})**"
221
+ else:
222
+ full_name = f"**[{data['name']} {model}]**"
223
+
224
+ if adv not in ["Không có ưu điểm", "", None]:
225
+ table_data.append([full_name, adv])
226
+
227
+ if table_data:
228
+ df = pd.DataFrame(table_data, columns=columns)
229
+ else:
230
+ df = pd.DataFrame([["Không có ưu điểm", ""]], columns=columns)
231
+
232
+ markdown_table = df.to_markdown(index=False)
233
+ # Fix: Use proper ChatInterface message format
234
+ history.append(
235
+ {"role": "assistant", "content": f"💡 Ưu điểm nổi trội\n{markdown_table}"})
236
+ return history
237
+
238
+
239
+ def show_solution_packages(state, history=None):
240
+ """Show solution packages in a structured format"""
241
+ specs_map = state.get("specs_advantages", {})
242
+ if history is None:
243
+ history = []
244
+
245
+ if not specs_map:
246
+ # Fix: Use proper ChatInterface message format
247
+ history.append(
248
+ {"role": "assistant", "content": "📦 Không có gói sản phẩm nào"})
249
+ return history
250
+
251
+ # Filter only solution packages
252
+ solution_packages = {}
253
+ for key, data in specs_map.items():
254
+ if data.get("model") == "Gói giải pháp":
255
+ solution_packages[key] = data
256
+
257
+ if not solution_packages:
258
+ # Fix: Use proper ChatInterface message format
259
+ history.append(
260
+ {"role": "assistant", "content": "📦 Không có gói sản phẩm nào"})
261
+ return history
262
+
263
+ # Build markdown content for each package
264
+ markdown_content = "## 📦 Gói sản phẩm\n\n"
265
+
266
+ for key, data in solution_packages.items():
267
+ spec_content = data.get("specification", "")
268
+ markdown_content += spec_content + "\n\n"
269
+
270
+ # Fix: Use proper ChatInterface message format
271
+ history.append({"role": "assistant", "content": markdown_content})
272
+ return history
273
+
274
+
275
+ css = """
276
+ .icon-button-wrapper.top-panel.hide-top-corner,
277
+ .icon-button-wrapper.top-panel button[aria-label="Clear"],
278
+ .icon-button-wrapper.top-panel button[title="Clear"],
279
+ .chat-interface .clear-btn,
280
+ .chat-interface button[aria-label="Clear"],
281
+ .chat-interface button[title="Clear"],
282
+ .chat-interface .svelte-1aq8tno button:last-child,
283
+ .chat-interface .action-buttons button:last-child {
284
+ display: none !important;
285
+ visibility: hidden !important;
286
+ }
287
+ .svelte-vuh1yp .prose.svelte-lag733 .md.svelte-7ddecg.prose h1,
288
+ .svelte-vuh1yp h1,
289
+ .prose.svelte-lag733 h1 {
290
+ visibility: hidden !important;
291
+ }
292
+ .top-right-clear {
293
+ position: absolute;
294
+ top: 10px;
295
+ right: 10px;
296
+ z-index: 1000;
297
+ }
298
+ .custom-button-row {
299
+ margin-top: -10px;
300
+ gap: 8px;
301
+ justify-content: flex-start;
302
+ }
303
+ .custom-clear-btn {
304
+ background: linear-gradient(135deg, #ff6b6b, #ee5a24) !important;
305
+ color: white !important;
306
+ border: none !important;
307
+ border-radius: 6px !important;
308
+ font-weight: 500 !important;
309
+ transition: all 0.3s ease !important;
310
+ min-width: 80px !important;
311
+ }
312
+ .custom-clear-btn:hover {
313
+ background: linear-gradient(135deg, #ee5a24, #ff6b6b) !important;
314
+ transform: translateY(-1px) !important;
315
+ box-shadow: 0 4px 12px rgba(238, 90, 36, 0.3) !important;
316
+ }
317
+ .spec-adv-btn {
318
+ background: linear-gradient(135deg, #4834d4, #686de0) !important;
319
+ color: white !important;
320
+ border: none !important;
321
+ border-radius: 6px !important;
322
+ font-weight: 500 !important;
323
+ transition: all 0.3s ease !important;
324
+ }
325
+ .spec-adv-btn:hover {
326
+ background: linear-gradient(135deg, #686de0, #4834d4) !important;
327
+ transform: translateY(-1px) !important;
328
+ box-shadow: 0 4px 12px rgba(72, 52, 212, 0.3) !important;
329
+ }
330
+ .gradio-container {
331
+ position: relative;
332
+ }
333
+ .model-dropdown, .debug-dropdown {
334
+ background: linear-gradient(135deg, #667eea, #764ba2) !important;
335
+ color: white !important;
336
+ border: none !important;
337
+ border-radius: 6px !important;
338
+ font-weight: 500 !important;
339
+ font-size: 13px !important;
340
+ transition: all 0.3s ease !important;
341
+ min-height: 32px !important;
342
+ box-shadow: 0 2px 4px rgba(0,0,0,0.15) !important;
343
+ }
344
+ .model-dropdown select, .debug-dropdown select {
345
+ color: white !important;
346
+ background: transparent !important;
347
+ cursor: pointer !important;
348
+ }
349
+ .model-dropdown select:focus, .debug-dropdown select:focus {
350
+ outline: none;
351
+ }
352
+ .model-dropdown select:not(:focus), .debug-dropdown select:not(:focus) {
353
+ pointer-events: auto;
354
+ }
355
+ """
356
+
357
+ with gr.Blocks(fill_height=True, css=css) as demo:
358
+ state = gr.State(value={})
359
+ raw_documents = gr.State(value={})
360
+
361
+ with gr.Row(elem_classes="top-right-clear"):
362
+ with gr.Column(scale=20):
363
+ gr.Markdown("### 🛍️ RangDong Sales Agent")
364
+
365
+ with gr.Column(scale=1, min_width=180):
366
+ model_dropdown = gr.Dropdown(
367
+ choices=["Gemini 2.0 Flash",
368
+ "Gemini 2.5 Flash Lite",
369
+ "Gemini 2.0 Flash Lite"],
370
+ value="Gemini 2.0 Flash",
371
+ label="Model",
372
+ show_label=False,
373
+ elem_classes="model-dropdown",
374
+ interactive=True,
375
+ container=False
376
+ )
377
+
378
+ with gr.Column(scale=1, min_width=120):
379
+ debug_dropdown = gr.Dropdown(
380
+ choices=["Normal", "Debug"],
381
+ value="Normal",
382
+ label="Mode",
383
+ show_label=False,
384
+ elem_classes="debug-dropdown",
385
+ interactive=True,
386
+ container=False
387
+ )
388
+
389
+ with gr.Column(scale=1, min_width=30):
390
+ clear_btn = gr.Button(
391
+ "✨ Xoá", variant="secondary", size="sm", elem_classes="custom-clear-btn")
392
+
393
+ chatbot = gr.Chatbot(
394
+ avatar_images=[
395
+ "https://cdn-icons-png.flaticon.com/512/219/219983.png",
396
+ "assets/agent.png"
397
+ ],
398
+ type="messages",
399
+ height=800
400
+ )
401
+
402
+ chat = gr.ChatInterface(
403
+ fn=respond_to_chat,
404
+ multimodal=True,
405
+ type="messages",
406
+ examples=[
407
+ ["Tìm sản phẩm bình gi��� nhiệt dung tích dưới 2 lít."],
408
+ ["Tìm sản phẩm ổ cắm thông minh"],
409
+ ["Tư vấn cho tôi đèn học chống cận cho con gái của tôi học lớp 6"]
410
+ ],
411
+ title="_",
412
+ additional_inputs=[state, model_dropdown, debug_dropdown],
413
+ chatbot=chatbot
414
+ )
415
+
416
+ with gr.Row(elem_classes="custom-button-row") as button_row:
417
+ btn_spec = gr.Button("📄 Thông số kỹ thuật",
418
+ variant="secondary", elem_classes="spec-adv-btn")
419
+ btn_adv = gr.Button("💡 Ưu điểm nổi trội",
420
+ variant="secondary", elem_classes="spec-adv-btn")
421
+ btn_pckg = gr.Button(
422
+ "📦 Gói sản phẩm", variant="secondary", elem_classes="spec-adv-btn")
423
+
424
+ # Event handlers
425
+ btn_spec.click(fn=show_specs, inputs=[state, chatbot], outputs=[chatbot])
426
+ btn_adv.click(fn=show_advantages,
427
+ inputs=[state, chatbot],
428
+ outputs=[chatbot])
429
+
430
+ # Gói sản phẩm button shows solution packages in structured format
431
+ btn_pckg.click(fn=show_solution_packages,
432
+ inputs=[state, chatbot],
433
+ outputs=[chatbot])
434
+
435
+ # Model change handler -> call API
436
+ def _on_model_change(model_name):
437
+ try:
438
+ requests.post(f"{API_BASE_URL}/set_model",
439
+ json={"model_name": model_name})
440
+ except Exception as e:
441
+ print(f"Warning: set_model failed: {e}")
442
+
443
+ model_dropdown.change(fn=_on_model_change,
444
+ inputs=[model_dropdown],
445
+ outputs=[]
446
+ ) # type: ignore[attr-defined]
447
+
448
+ # Clear button - clear all ChatInterface internal components
449
+ clear_btn.click(
450
+ fn=clear_chat,
451
+ inputs=[],
452
+ outputs=[chatbot, state, raw_documents,
453
+ chat.chatbot_state, chat.textbox]
454
+ )
455
+
456
+ if __name__ == "__main__":
457
+ demo.launch()