Spaces:
Sleeping
Sleeping
Fix bug về button Thông Số Kỹ Thuật và button Ưu điểm - Phải lấy theo sản phẩm (tập sản phẩm) của câu trả lời hiện tại
Browse files
app.py
CHANGED
|
@@ -4,8 +4,9 @@ import chainlit as cl
|
|
| 4 |
import pandas as pd
|
| 5 |
import requests
|
| 6 |
import asyncio
|
| 7 |
-
from typing import Dict, Any, Optional, Callable
|
| 8 |
from dataclasses import dataclass, field
|
|
|
|
| 9 |
|
| 10 |
|
| 11 |
API_BASE_URL = "https://sale-agent-m179.onrender.com"
|
|
@@ -15,6 +16,7 @@ API_BASE_URL = "https://sale-agent-m179.onrender.com"
|
|
| 15 |
class ConversationState:
|
| 16 |
"""Data class to hold conversation state"""
|
| 17 |
specs_advantages: Dict[str, Any] = field(default_factory=dict)
|
|
|
|
| 18 |
raw_documents: Optional[Dict[str, Any]] = None
|
| 19 |
outputs: Optional[Dict[str, Any]] = None
|
| 20 |
selected_model: str = "Gemini 2.0 Flash"
|
|
@@ -22,6 +24,7 @@ class ConversationState:
|
|
| 22 |
def reset(self):
|
| 23 |
"""Reset state to initial values"""
|
| 24 |
self.specs_advantages = {}
|
|
|
|
| 25 |
self.raw_documents = None
|
| 26 |
self.outputs = None
|
| 27 |
self.selected_model = "Gemini 2.0 Flash"
|
|
@@ -88,25 +91,54 @@ class ChatService:
|
|
| 88 |
j = resp.json()
|
| 89 |
response = j.get("response", "")
|
| 90 |
specs_advantages = j.get("specs_advantages")
|
|
|
|
| 91 |
raw_documents = j.get("raw_documents")
|
| 92 |
outputs = j.get("outputs")
|
| 93 |
else:
|
| 94 |
response = f"Error: API status {resp.status_code}"
|
| 95 |
-
specs_advantages, raw_documents, outputs = None, None, None
|
| 96 |
except Exception as e:
|
| 97 |
response = f"Error calling API: {e}"
|
| 98 |
-
specs_advantages, raw_documents, outputs = None, None, None
|
| 99 |
|
| 100 |
end = time.perf_counter()
|
| 101 |
|
| 102 |
# Update state
|
| 103 |
-
|
| 104 |
-
|
| 105 |
state.raw_documents = raw_documents
|
| 106 |
state.outputs = outputs
|
| 107 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 108 |
return response + f"\n\n*Thời gian xử lí: {end - start:.6f}s*"
|
| 109 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 110 |
|
| 111 |
class DisplayService:
|
| 112 |
"""Handles display-related operations"""
|
|
@@ -286,13 +318,6 @@ class UIService:
|
|
| 286 |
cl.Action(name="change_model", value="model", label="🔄 Đổi model", payload={"action": "model"}),
|
| 287 |
]
|
| 288 |
|
| 289 |
-
@staticmethod
|
| 290 |
-
def create_start_buttons():
|
| 291 |
-
"""Create persistent action buttons"""
|
| 292 |
-
return [
|
| 293 |
-
cl.Action(name="change_model", value="model", label="🔄 Đổi model", payload={"action": "model"}),
|
| 294 |
-
]
|
| 295 |
-
|
| 296 |
@staticmethod
|
| 297 |
async def send_message_with_buttons(content: str, actions=None, author="assistant"):
|
| 298 |
"""Send message with optional action buttons and author"""
|
|
@@ -313,7 +338,7 @@ class UIService:
|
|
| 313 |
# Typing animation frames
|
| 314 |
typing_frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
|
| 315 |
|
| 316 |
-
for i in range(
|
| 317 |
frame = typing_frames[i % len(typing_frames)]
|
| 318 |
msg.content = f"{frame} Đang suy nghĩ..."
|
| 319 |
await msg.update()
|
|
@@ -336,9 +361,9 @@ async def on_chat_start():
|
|
| 336 |
).send()
|
| 337 |
|
| 338 |
# Create initial action buttons
|
| 339 |
-
actions = UIService.
|
| 340 |
await cl.Message(
|
| 341 |
-
content="Sử dụng nút bên dưới để
|
| 342 |
actions=actions,
|
| 343 |
author="assistant"
|
| 344 |
).send()
|
|
|
|
| 4 |
import pandas as pd
|
| 5 |
import requests
|
| 6 |
import asyncio
|
| 7 |
+
from typing import Dict, List, Any, Optional, Callable
|
| 8 |
from dataclasses import dataclass, field
|
| 9 |
+
import os
|
| 10 |
|
| 11 |
|
| 12 |
API_BASE_URL = "https://sale-agent-m179.onrender.com"
|
|
|
|
| 16 |
class ConversationState:
|
| 17 |
"""Data class to hold conversation state"""
|
| 18 |
specs_advantages: Dict[str, Any] = field(default_factory=dict)
|
| 19 |
+
solution_packages: List[str] = field(default_factory=list)
|
| 20 |
raw_documents: Optional[Dict[str, Any]] = None
|
| 21 |
outputs: Optional[Dict[str, Any]] = None
|
| 22 |
selected_model: str = "Gemini 2.0 Flash"
|
|
|
|
| 24 |
def reset(self):
|
| 25 |
"""Reset state to initial values"""
|
| 26 |
self.specs_advantages = {}
|
| 27 |
+
self.solution_packages = []
|
| 28 |
self.raw_documents = None
|
| 29 |
self.outputs = None
|
| 30 |
self.selected_model = "Gemini 2.0 Flash"
|
|
|
|
| 91 |
j = resp.json()
|
| 92 |
response = j.get("response", "")
|
| 93 |
specs_advantages = j.get("specs_advantages")
|
| 94 |
+
solution_packages = j.get("solution_packages")
|
| 95 |
raw_documents = j.get("raw_documents")
|
| 96 |
outputs = j.get("outputs")
|
| 97 |
else:
|
| 98 |
response = f"Error: API status {resp.status_code}"
|
| 99 |
+
specs_advantages, solution_packages, raw_documents, outputs = None, None, None, None
|
| 100 |
except Exception as e:
|
| 101 |
response = f"Error calling API: {e}"
|
| 102 |
+
specs_advantages, solution_packages, raw_documents, outputs = None, None, None, None
|
| 103 |
|
| 104 |
end = time.perf_counter()
|
| 105 |
|
| 106 |
# Update state
|
| 107 |
+
state.specs_advantages = specs_advantages
|
| 108 |
+
state.solution_packages = solution_packages
|
| 109 |
state.raw_documents = raw_documents
|
| 110 |
state.outputs = outputs
|
| 111 |
|
| 112 |
+
# Filter products based on query - FIX: Call static method correctly
|
| 113 |
+
if state.specs_advantages is not None:
|
| 114 |
+
ChatService.get_specific_product_from_query(message, state)
|
| 115 |
+
|
| 116 |
return response + f"\n\n*Thời gian xử lí: {end - start:.6f}s*"
|
| 117 |
|
| 118 |
+
@staticmethod
|
| 119 |
+
def get_specific_product_from_query(query, state):
|
| 120 |
+
"""Filter specs_advantages based on models found in query"""
|
| 121 |
+
specs_map = state.specs_advantages or {}
|
| 122 |
+
product_model_list = []
|
| 123 |
+
|
| 124 |
+
for prod_id, data in specs_map.items():
|
| 125 |
+
model = data.get("model", None)
|
| 126 |
+
if model is not None:
|
| 127 |
+
product_model_list.append(model)
|
| 128 |
+
|
| 129 |
+
found_models = []
|
| 130 |
+
for model in product_model_list:
|
| 131 |
+
pattern = re.escape(model)
|
| 132 |
+
if re.search(pattern, query, re.IGNORECASE):
|
| 133 |
+
found_models.append(model)
|
| 134 |
+
|
| 135 |
+
new_specs_advantages = {}
|
| 136 |
+
if found_models: # FIX: Changed from != [] to truthy check
|
| 137 |
+
for prod_id, data in specs_map.items():
|
| 138 |
+
if data.get("model", None) in found_models:
|
| 139 |
+
new_specs_advantages[prod_id] = data
|
| 140 |
+
|
| 141 |
+
state.specs_advantages = new_specs_advantages
|
| 142 |
|
| 143 |
class DisplayService:
|
| 144 |
"""Handles display-related operations"""
|
|
|
|
| 318 |
cl.Action(name="change_model", value="model", label="🔄 Đổi model", payload={"action": "model"}),
|
| 319 |
]
|
| 320 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 321 |
@staticmethod
|
| 322 |
async def send_message_with_buttons(content: str, actions=None, author="assistant"):
|
| 323 |
"""Send message with optional action buttons and author"""
|
|
|
|
| 338 |
# Typing animation frames
|
| 339 |
typing_frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
|
| 340 |
|
| 341 |
+
for i in range(8): # Show animation for ~2 seconds
|
| 342 |
frame = typing_frames[i % len(typing_frames)]
|
| 343 |
msg.content = f"{frame} Đang suy nghĩ..."
|
| 344 |
await msg.update()
|
|
|
|
| 361 |
).send()
|
| 362 |
|
| 363 |
# Create initial action buttons
|
| 364 |
+
actions = UIService.create_action_buttons()
|
| 365 |
await cl.Message(
|
| 366 |
+
content="Sử dụng các nút bên dưới để:",
|
| 367 |
actions=actions,
|
| 368 |
author="assistant"
|
| 369 |
).send()
|