Spaces:
Running
Running
Bổ sung tính năng tìm theo mã sản phẩm
Browse files
app.py
CHANGED
|
@@ -20,6 +20,7 @@ class ConversationState:
|
|
| 20 |
raw_documents: Optional[Dict[str, Any]] = None
|
| 21 |
outputs: Optional[Dict[str, Any]] = None
|
| 22 |
selected_model: str = "Gemini 2.0 Flash"
|
|
|
|
| 23 |
|
| 24 |
def reset(self):
|
| 25 |
"""Reset state to initial values"""
|
|
@@ -28,6 +29,7 @@ class ConversationState:
|
|
| 28 |
self.raw_documents = None
|
| 29 |
self.outputs = None
|
| 30 |
self.selected_model = "Gemini 2.0 Flash"
|
|
|
|
| 31 |
|
| 32 |
|
| 33 |
class StateManager:
|
|
@@ -59,6 +61,11 @@ class StateManager:
|
|
| 59 |
state.selected_model = model_name
|
| 60 |
except Exception as e:
|
| 61 |
print(f"Warning: set_model failed: {e}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 62 |
|
| 63 |
|
| 64 |
class ChatService:
|
|
@@ -71,7 +78,7 @@ class ChatService:
|
|
| 71 |
image_path: Optional[str] = None
|
| 72 |
) -> str:
|
| 73 |
"""Handle chat responses with image support"""
|
| 74 |
-
print(f"🔄 === DEBUG STATE ===\n Chat request with model: {state.selected_model}")
|
| 75 |
start = time.perf_counter()
|
| 76 |
|
| 77 |
# Call API
|
|
@@ -79,11 +86,18 @@ class ChatService:
|
|
| 79 |
if image_path:
|
| 80 |
with open(image_path, 'rb') as f:
|
| 81 |
files = {"image": f}
|
| 82 |
-
data = {
|
|
|
|
|
|
|
|
|
|
| 83 |
resp = requests.post(
|
| 84 |
f"{API_BASE_URL}/chat_with_image", files=files, data=data, timeout=120)
|
| 85 |
else:
|
| 86 |
-
payload = {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 87 |
resp = requests.post(f"{API_BASE_URL}/chat",
|
| 88 |
json=payload, timeout=120)
|
| 89 |
|
|
@@ -286,24 +300,7 @@ class DisplayService:
|
|
| 286 |
if not packages or packages == []:
|
| 287 |
return "📦 **Gói sản phẩm**\n\nKhông có gói sản phẩm nào"
|
| 288 |
|
| 289 |
-
# # Filter only solution packages
|
| 290 |
-
# solution_packages = {}
|
| 291 |
-
# for key, data in specs_map.items():
|
| 292 |
-
# if data.get("model") == "Gói giải pháp":
|
| 293 |
-
# solution_packages[key] = data
|
| 294 |
-
|
| 295 |
-
# if not solution_packages:
|
| 296 |
-
# return "📦 **Gói sản phẩm**\n\nKhông có gói sản phẩm nào"
|
| 297 |
-
|
| 298 |
-
# # Build markdown content for each package
|
| 299 |
-
# markdown_content = "## 📦 Gói sản phẩm\n\n"
|
| 300 |
-
|
| 301 |
-
# for key, data in solution_packages.items():
|
| 302 |
-
# spec_content = data.get("specification", "")
|
| 303 |
-
# markdown_content += spec_content + "\n\n"
|
| 304 |
-
|
| 305 |
markdown_table = "\n\n".join(packages)
|
| 306 |
-
|
| 307 |
return markdown_table
|
| 308 |
|
| 309 |
|
|
@@ -311,26 +308,34 @@ class UIService:
|
|
| 311 |
"""Handles UI-related operations"""
|
| 312 |
|
| 313 |
@staticmethod
|
| 314 |
-
def create_action_buttons():
|
| 315 |
"""Create persistent action buttons"""
|
|
|
|
|
|
|
|
|
|
| 316 |
return [
|
| 317 |
cl.Action(name="show_specs", value="specs", label="📄 Thông số kỹ thuật", payload={"action": "specs"}),
|
| 318 |
cl.Action(name="show_advantages", value="advantages", label="💡 Ưu điểm nổi trội", payload={"action": "advantages"}),
|
| 319 |
cl.Action(name="show_packages", value="packages", label="📦 Gói sản phẩm", payload={"action": "packages"}),
|
|
|
|
| 320 |
cl.Action(name="change_model", value="model", label="🔄 Đổi model", payload={"action": "model"}),
|
| 321 |
]
|
| 322 |
|
| 323 |
-
|
|
|
|
| 324 |
"""Create start buttons"""
|
|
|
|
|
|
|
| 325 |
return [
|
|
|
|
| 326 |
cl.Action(name="change_model", value="model", label="🔄 Đổi model", payload={"action": "model"}),
|
| 327 |
]
|
| 328 |
|
| 329 |
@staticmethod
|
| 330 |
-
async def send_message_with_buttons(content: str, actions=None, author="assistant"):
|
| 331 |
"""Send message with optional action buttons and author"""
|
| 332 |
if actions is None:
|
| 333 |
-
actions = UIService.create_action_buttons()
|
| 334 |
await cl.Message(
|
| 335 |
content=content,
|
| 336 |
actions=actions,
|
|
@@ -369,9 +374,9 @@ async def on_chat_start():
|
|
| 369 |
).send()
|
| 370 |
|
| 371 |
# Create initial action buttons
|
| 372 |
-
actions = UIService.create_start_buttons()
|
| 373 |
await cl.Message(
|
| 374 |
-
content="Sử dụng nút bên dưới để
|
| 375 |
actions=actions,
|
| 376 |
author="assistant"
|
| 377 |
).send()
|
|
@@ -381,21 +386,37 @@ async def on_chat_start():
|
|
| 381 |
async def on_show_specs(action):
|
| 382 |
"""Handle show specifications action"""
|
| 383 |
specs_content = DisplayService.show_specs(app_state)
|
| 384 |
-
await UIService.send_message_with_buttons(specs_content, author="assistant")
|
| 385 |
|
| 386 |
|
| 387 |
@cl.action_callback("show_advantages")
|
| 388 |
async def on_show_advantages(action):
|
| 389 |
"""Handle show advantages action"""
|
| 390 |
adv_content = DisplayService.show_advantages(app_state)
|
| 391 |
-
await UIService.send_message_with_buttons(adv_content, author="assistant")
|
| 392 |
|
| 393 |
|
| 394 |
@cl.action_callback("show_packages")
|
| 395 |
async def on_show_packages(action):
|
| 396 |
"""Handle show packages action"""
|
| 397 |
pkg_content = DisplayService.show_solution_packages(app_state)
|
| 398 |
-
await UIService.send_message_with_buttons(pkg_content, author="assistant")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 399 |
|
| 400 |
|
| 401 |
@cl.action_callback("change_model")
|
|
@@ -415,7 +436,7 @@ async def on_change_model(action):
|
|
| 415 |
)
|
| 416 |
|
| 417 |
await cl.Message(
|
| 418 |
-
content=f"**Model hiện tại**: {app_state.selected_model}\n\nChọn model mới:",
|
| 419 |
actions=model_actions,
|
| 420 |
author="assistant"
|
| 421 |
).send()
|
|
@@ -424,7 +445,7 @@ async def on_change_model(action):
|
|
| 424 |
@cl.action_callback("back_to_main")
|
| 425 |
async def on_back_to_main(action):
|
| 426 |
"""Handle back to main menu action"""
|
| 427 |
-
actions = UIService.create_action_buttons()
|
| 428 |
await cl.Message(
|
| 429 |
content="📋 **Menu chính**\n\nSử dụng các nút bên dưới để:",
|
| 430 |
actions=actions,
|
|
@@ -435,19 +456,19 @@ async def on_back_to_main(action):
|
|
| 435 |
@cl.action_callback("select_model_0")
|
| 436 |
async def on_select_model_0(action):
|
| 437 |
StateManager.change_model(app_state, "Gemini 2.0 Flash")
|
| 438 |
-
await UIService.send_message_with_buttons("✅ Đã chuyển sang **Gemini 2.0 Flash**", author="assistant")
|
| 439 |
|
| 440 |
|
| 441 |
@cl.action_callback("select_model_1")
|
| 442 |
async def on_select_model_1(action):
|
| 443 |
StateManager.change_model(app_state, "Gemini 2.5 Flash Lite")
|
| 444 |
-
await UIService.send_message_with_buttons("✅ Đã chuyển sang **Gemini 2.5 Flash Lite**", author="assistant")
|
| 445 |
|
| 446 |
|
| 447 |
@cl.action_callback("select_model_2")
|
| 448 |
async def on_select_model_2(action):
|
| 449 |
StateManager.change_model(app_state, "Gemini 2.0 Flash Lite")
|
| 450 |
-
await UIService.send_message_with_buttons("✅ Đã chuyển sang **Gemini 2.0 Flash Lite**", author="assistant")
|
| 451 |
|
| 452 |
|
| 453 |
@cl.on_message
|
|
@@ -469,6 +490,6 @@ async def main(message: cl.Message):
|
|
| 469 |
|
| 470 |
# Update the typing message with final response and buttons
|
| 471 |
typing_msg.content = response
|
| 472 |
-
typing_msg.actions = UIService.create_action_buttons()
|
| 473 |
typing_msg.author = "assistant" # Ensure author is set
|
| 474 |
await typing_msg.update()
|
|
|
|
| 20 |
raw_documents: Optional[Dict[str, Any]] = None
|
| 21 |
outputs: Optional[Dict[str, Any]] = None
|
| 22 |
selected_model: str = "Gemini 2.0 Flash"
|
| 23 |
+
product_model_search: bool = False
|
| 24 |
|
| 25 |
def reset(self):
|
| 26 |
"""Reset state to initial values"""
|
|
|
|
| 29 |
self.raw_documents = None
|
| 30 |
self.outputs = None
|
| 31 |
self.selected_model = "Gemini 2.0 Flash"
|
| 32 |
+
self.product_model_search = False
|
| 33 |
|
| 34 |
|
| 35 |
class StateManager:
|
|
|
|
| 61 |
state.selected_model = model_name
|
| 62 |
except Exception as e:
|
| 63 |
print(f"Warning: set_model failed: {e}")
|
| 64 |
+
|
| 65 |
+
@staticmethod
|
| 66 |
+
def toggle_product_model_search(state: ConversationState):
|
| 67 |
+
"""Toggle product model search mode"""
|
| 68 |
+
state.product_model_search = not state.product_model_search
|
| 69 |
|
| 70 |
|
| 71 |
class ChatService:
|
|
|
|
| 78 |
image_path: Optional[str] = None
|
| 79 |
) -> str:
|
| 80 |
"""Handle chat responses with image support"""
|
| 81 |
+
print(f"🔄 === DEBUG STATE ===\n Chat request with model: {state.selected_model}, Product Model Search: {state.product_model_search}")
|
| 82 |
start = time.perf_counter()
|
| 83 |
|
| 84 |
# Call API
|
|
|
|
| 86 |
if image_path:
|
| 87 |
with open(image_path, 'rb') as f:
|
| 88 |
files = {"image": f}
|
| 89 |
+
data = {
|
| 90 |
+
"message": message,
|
| 91 |
+
"product_model_search": str(state.product_model_search).lower()
|
| 92 |
+
}
|
| 93 |
resp = requests.post(
|
| 94 |
f"{API_BASE_URL}/chat_with_image", files=files, data=data, timeout=120)
|
| 95 |
else:
|
| 96 |
+
payload = {
|
| 97 |
+
"message": message,
|
| 98 |
+
"debug": "Normal",
|
| 99 |
+
"product_model_search": state.product_model_search
|
| 100 |
+
}
|
| 101 |
resp = requests.post(f"{API_BASE_URL}/chat",
|
| 102 |
json=payload, timeout=120)
|
| 103 |
|
|
|
|
| 300 |
if not packages or packages == []:
|
| 301 |
return "📦 **Gói sản phẩm**\n\nKhông có gói sản phẩm nào"
|
| 302 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 303 |
markdown_table = "\n\n".join(packages)
|
|
|
|
| 304 |
return markdown_table
|
| 305 |
|
| 306 |
|
|
|
|
| 308 |
"""Handles UI-related operations"""
|
| 309 |
|
| 310 |
@staticmethod
|
| 311 |
+
def create_action_buttons(state: ConversationState):
|
| 312 |
"""Create persistent action buttons"""
|
| 313 |
+
# Determine the product search button text and icon
|
| 314 |
+
search_status = "🔍 Tìm theo mã sản phẩm (Đang tắt)" if not state.product_model_search else "🔍 Tìm theo mã sản phẩm (Đang bật)"
|
| 315 |
+
|
| 316 |
return [
|
| 317 |
cl.Action(name="show_specs", value="specs", label="📄 Thông số kỹ thuật", payload={"action": "specs"}),
|
| 318 |
cl.Action(name="show_advantages", value="advantages", label="💡 Ưu điểm nổi trội", payload={"action": "advantages"}),
|
| 319 |
cl.Action(name="show_packages", value="packages", label="📦 Gói sản phẩm", payload={"action": "packages"}),
|
| 320 |
+
cl.Action(name="toggle_product_search", value="toggle_search", label=search_status, payload={"action": "toggle_search"}),
|
| 321 |
cl.Action(name="change_model", value="model", label="🔄 Đổi model", payload={"action": "model"}),
|
| 322 |
]
|
| 323 |
|
| 324 |
+
@staticmethod
|
| 325 |
+
def create_start_buttons(state: ConversationState):
|
| 326 |
"""Create start buttons"""
|
| 327 |
+
search_status = "🔍 Tìm theo mã sản phẩm (Đang tắt)" if not state.product_model_search else "🔍 Tìm theo mã sản phẩm (Đang bật)"
|
| 328 |
+
|
| 329 |
return [
|
| 330 |
+
cl.Action(name="toggle_product_search", value="toggle_search", label=search_status, payload={"action": "toggle_search"}),
|
| 331 |
cl.Action(name="change_model", value="model", label="🔄 Đổi model", payload={"action": "model"}),
|
| 332 |
]
|
| 333 |
|
| 334 |
@staticmethod
|
| 335 |
+
async def send_message_with_buttons(content: str, state: ConversationState, actions=None, author="assistant"):
|
| 336 |
"""Send message with optional action buttons and author"""
|
| 337 |
if actions is None:
|
| 338 |
+
actions = UIService.create_action_buttons(state)
|
| 339 |
await cl.Message(
|
| 340 |
content=content,
|
| 341 |
actions=actions,
|
|
|
|
| 374 |
).send()
|
| 375 |
|
| 376 |
# Create initial action buttons
|
| 377 |
+
actions = UIService.create_start_buttons(app_state)
|
| 378 |
await cl.Message(
|
| 379 |
+
content="Sử dụng nút bên dưới để cấu hình:",
|
| 380 |
actions=actions,
|
| 381 |
author="assistant"
|
| 382 |
).send()
|
|
|
|
| 386 |
async def on_show_specs(action):
|
| 387 |
"""Handle show specifications action"""
|
| 388 |
specs_content = DisplayService.show_specs(app_state)
|
| 389 |
+
await UIService.send_message_with_buttons(specs_content, app_state, author="assistant")
|
| 390 |
|
| 391 |
|
| 392 |
@cl.action_callback("show_advantages")
|
| 393 |
async def on_show_advantages(action):
|
| 394 |
"""Handle show advantages action"""
|
| 395 |
adv_content = DisplayService.show_advantages(app_state)
|
| 396 |
+
await UIService.send_message_with_buttons(adv_content, app_state, author="assistant")
|
| 397 |
|
| 398 |
|
| 399 |
@cl.action_callback("show_packages")
|
| 400 |
async def on_show_packages(action):
|
| 401 |
"""Handle show packages action"""
|
| 402 |
pkg_content = DisplayService.show_solution_packages(app_state)
|
| 403 |
+
await UIService.send_message_with_buttons(pkg_content, app_state, author="assistant")
|
| 404 |
+
|
| 405 |
+
|
| 406 |
+
@cl.action_callback("toggle_product_search")
|
| 407 |
+
async def on_toggle_product_search(action):
|
| 408 |
+
"""Handle toggle product model search action"""
|
| 409 |
+
StateManager.toggle_product_model_search(app_state)
|
| 410 |
+
|
| 411 |
+
status_message = (
|
| 412 |
+
"✅ **Đã bật tìm kiếm theo mã sản phẩm**\n\n"
|
| 413 |
+
"Khi bạn nhắc đến mã/model cụ thể trong câu hỏi, hệ thống sẽ tìm kiếm chính xác theo mã đó."
|
| 414 |
+
if app_state.product_model_search
|
| 415 |
+
else "✅ **Đã tắt tìm kiếm theo mã sản phẩm**\n\n"
|
| 416 |
+
"Hệ thống sẽ tìm kiếm sản phẩm theo cách thông thường."
|
| 417 |
+
)
|
| 418 |
+
|
| 419 |
+
await UIService.send_message_with_buttons(status_message, app_state, author="assistant")
|
| 420 |
|
| 421 |
|
| 422 |
@cl.action_callback("change_model")
|
|
|
|
| 436 |
)
|
| 437 |
|
| 438 |
await cl.Message(
|
| 439 |
+
content=f"**Model hiện tại**: {app_state.selected_model}\n**Tìm kiếm theo mã**: {'Đang bật' if app_state.product_model_search else 'Đang tắt'}\n\nChọn model mới:",
|
| 440 |
actions=model_actions,
|
| 441 |
author="assistant"
|
| 442 |
).send()
|
|
|
|
| 445 |
@cl.action_callback("back_to_main")
|
| 446 |
async def on_back_to_main(action):
|
| 447 |
"""Handle back to main menu action"""
|
| 448 |
+
actions = UIService.create_action_buttons(app_state)
|
| 449 |
await cl.Message(
|
| 450 |
content="📋 **Menu chính**\n\nSử dụng các nút bên dưới để:",
|
| 451 |
actions=actions,
|
|
|
|
| 456 |
@cl.action_callback("select_model_0")
|
| 457 |
async def on_select_model_0(action):
|
| 458 |
StateManager.change_model(app_state, "Gemini 2.0 Flash")
|
| 459 |
+
await UIService.send_message_with_buttons("✅ Đã chuyển sang **Gemini 2.0 Flash**", app_state, author="assistant")
|
| 460 |
|
| 461 |
|
| 462 |
@cl.action_callback("select_model_1")
|
| 463 |
async def on_select_model_1(action):
|
| 464 |
StateManager.change_model(app_state, "Gemini 2.5 Flash Lite")
|
| 465 |
+
await UIService.send_message_with_buttons("✅ Đã chuyển sang **Gemini 2.5 Flash Lite**", app_state, author="assistant")
|
| 466 |
|
| 467 |
|
| 468 |
@cl.action_callback("select_model_2")
|
| 469 |
async def on_select_model_2(action):
|
| 470 |
StateManager.change_model(app_state, "Gemini 2.0 Flash Lite")
|
| 471 |
+
await UIService.send_message_with_buttons("✅ Đã chuyển sang **Gemini 2.0 Flash Lite**", app_state, author="assistant")
|
| 472 |
|
| 473 |
|
| 474 |
@cl.on_message
|
|
|
|
| 490 |
|
| 491 |
# Update the typing message with final response and buttons
|
| 492 |
typing_msg.content = response
|
| 493 |
+
typing_msg.actions = UIService.create_action_buttons(app_state)
|
| 494 |
typing_msg.author = "assistant" # Ensure author is set
|
| 495 |
await typing_msg.update()
|