update flow
Browse files- app/constants.py +9 -1
- app/embedding.py +8 -2
- app/main.py +7 -4
- app/sheets.py +2 -0
- app/supabase_db.py +7 -4
app/constants.py
CHANGED
|
@@ -1,3 +1,11 @@
|
|
| 1 |
VEHICLE_KEYWORDS = ["xe máy", "ô tô", "xe đạp", "xe hơi"]
|
| 2 |
SHEET_RANGE = 'chat!A2:F'
|
| 3 |
-
EMBEDDING_DIM = 1536
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
VEHICLE_KEYWORDS = ["xe máy", "ô tô", "xe đạp", "xe hơi"]
|
| 2 |
SHEET_RANGE = 'chat!A2:F'
|
| 3 |
+
EMBEDDING_DIM = 1536
|
| 4 |
+
|
| 5 |
+
# Mapping từ từ khóa sang tên cột trong bảng tblPhuongtien
|
| 6 |
+
VEHICLE_KEYWORD_TO_COLUMN = {
|
| 7 |
+
"xe máy": "xemay",
|
| 8 |
+
"ô tô": "oto",
|
| 9 |
+
"xe đạp": "xedap",
|
| 10 |
+
"xe hơi": "xehoi"
|
| 11 |
+
}
|
app/embedding.py
CHANGED
|
@@ -47,10 +47,16 @@ class EmbeddingClient:
|
|
| 47 |
json={"text": text}
|
| 48 |
)
|
| 49 |
response.raise_for_status()
|
| 50 |
-
|
| 51 |
-
|
|
|
|
| 52 |
except Exception as e:
|
| 53 |
logger.error(f"Error creating embedding: {e}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
raise
|
| 55 |
|
| 56 |
@timing_decorator_sync
|
|
|
|
| 47 |
json={"text": text}
|
| 48 |
)
|
| 49 |
response.raise_for_status()
|
| 50 |
+
data = await response.json()
|
| 51 |
+
logger.info(f"[DEBUG] Embedding API response: {data}")
|
| 52 |
+
return data["embedding"]
|
| 53 |
except Exception as e:
|
| 54 |
logger.error(f"Error creating embedding: {e}")
|
| 55 |
+
if 'response' in locals():
|
| 56 |
+
try:
|
| 57 |
+
logger.error(f"Embedding API status: {response.status_code}, content: {await response.aread()}")
|
| 58 |
+
except Exception as ex:
|
| 59 |
+
logger.error(f"Error reading response content: {ex}")
|
| 60 |
raise
|
| 61 |
|
| 62 |
@timing_decorator_sync
|
app/main.py
CHANGED
|
@@ -13,7 +13,7 @@ from .sheets import SheetsClient
|
|
| 13 |
from .supabase_db import SupabaseClient
|
| 14 |
from .embedding import EmbeddingClient
|
| 15 |
from .utils import setup_logging, extract_command, extract_keywords, timing_decorator_async, timing_decorator_sync, ensure_log_dir, validate_config
|
| 16 |
-
from .constants import VEHICLE_KEYWORDS, SHEET_RANGE
|
| 17 |
from .health import router as health_router
|
| 18 |
|
| 19 |
app = FastAPI(title="WeBot Facebook Messenger API")
|
|
@@ -95,6 +95,8 @@ async def webhook(request: Request):
|
|
| 95 |
Input: request (Request) - request chứa payload JSON từ Facebook.
|
| 96 |
Output: JSON status.
|
| 97 |
"""
|
|
|
|
|
|
|
| 98 |
body_bytes = await request.body()
|
| 99 |
|
| 100 |
# Verify request is from Facebook
|
|
@@ -127,11 +129,12 @@ async def process_message(message_data: Dict[str, Any]):
|
|
| 127 |
|
| 128 |
# Nếu không có message_text và attachments, không xử lý
|
| 129 |
if not message_text and not attachments:
|
|
|
|
| 130 |
return
|
| 131 |
|
| 132 |
# Get page access token (sync)
|
| 133 |
page_token = supabase_client.get_page_token(page_id)
|
| 134 |
-
logger.info(f"[DEBUG] page_token: {page_token}")
|
| 135 |
|
| 136 |
# Nếu không có page_token, không xử lý
|
| 137 |
if not page_token:
|
|
@@ -170,7 +173,7 @@ async def process_message(message_data: Dict[str, Any]):
|
|
| 170 |
# Có thông tin phương tiện
|
| 171 |
embedding = await embedding_client.create_embedding(message_text)
|
| 172 |
logger.info(f"[DEBUG] embedding: {embedding[:5]} ... (total {len(embedding)})")
|
| 173 |
-
matches = supabase_client.match_documents(embedding,
|
| 174 |
logger.info(f"[DEBUG] matches: {matches}")
|
| 175 |
if matches:
|
| 176 |
response = format_search_results(matches)
|
|
@@ -200,7 +203,7 @@ async def process_message(message_data: Dict[str, Any]):
|
|
| 200 |
# Có thông tin phương tiện
|
| 201 |
embedding = await embedding_client.create_embedding(message_text)
|
| 202 |
logger.info(f"[DEBUG] embedding: {embedding[:5]} ... (total {len(embedding)})")
|
| 203 |
-
matches = supabase_client.match_documents(embedding,
|
| 204 |
logger.info(f"[DEBUG] matches: {matches}")
|
| 205 |
if matches:
|
| 206 |
response = format_search_results(matches)
|
|
|
|
| 13 |
from .supabase_db import SupabaseClient
|
| 14 |
from .embedding import EmbeddingClient
|
| 15 |
from .utils import setup_logging, extract_command, extract_keywords, timing_decorator_async, timing_decorator_sync, ensure_log_dir, validate_config
|
| 16 |
+
from .constants import VEHICLE_KEYWORDS, SHEET_RANGE, VEHICLE_KEYWORD_TO_COLUMN
|
| 17 |
from .health import router as health_router
|
| 18 |
|
| 19 |
app = FastAPI(title="WeBot Facebook Messenger API")
|
|
|
|
| 95 |
Input: request (Request) - request chứa payload JSON từ Facebook.
|
| 96 |
Output: JSON status.
|
| 97 |
"""
|
| 98 |
+
|
| 99 |
+
logger.info(f"[DEBUG] Nhận message từ Facebook Messenger webhook...")
|
| 100 |
body_bytes = await request.body()
|
| 101 |
|
| 102 |
# Verify request is from Facebook
|
|
|
|
| 129 |
|
| 130 |
# Nếu không có message_text và attachments, không xử lý
|
| 131 |
if not message_text and not attachments:
|
| 132 |
+
logger.info(f"[DEBUG] Không có message_text và attachments, không xử lý...")
|
| 133 |
return
|
| 134 |
|
| 135 |
# Get page access token (sync)
|
| 136 |
page_token = supabase_client.get_page_token(page_id)
|
| 137 |
+
logger.info(f"[DEBUG] page_token: {page_token[:10]} ... {page_token[-10:]}")
|
| 138 |
|
| 139 |
# Nếu không có page_token, không xử lý
|
| 140 |
if not page_token:
|
|
|
|
| 173 |
# Có thông tin phương tiện
|
| 174 |
embedding = await embedding_client.create_embedding(message_text)
|
| 175 |
logger.info(f"[DEBUG] embedding: {embedding[:5]} ... (total {len(embedding)})")
|
| 176 |
+
matches = supabase_client.match_documents(embedding, vehicle_keywords=keywords)
|
| 177 |
logger.info(f"[DEBUG] matches: {matches}")
|
| 178 |
if matches:
|
| 179 |
response = format_search_results(matches)
|
|
|
|
| 203 |
# Có thông tin phương tiện
|
| 204 |
embedding = await embedding_client.create_embedding(message_text)
|
| 205 |
logger.info(f"[DEBUG] embedding: {embedding[:5]} ... (total {len(embedding)})")
|
| 206 |
+
matches = supabase_client.match_documents(embedding, vehicle_keywords=keywords)
|
| 207 |
logger.info(f"[DEBUG] matches: {matches}")
|
| 208 |
if matches:
|
| 209 |
response = format_search_results(matches)
|
app/sheets.py
CHANGED
|
@@ -90,6 +90,8 @@ class SheetsClient:
|
|
| 90 |
history = []
|
| 91 |
|
| 92 |
for row in values:
|
|
|
|
|
|
|
| 93 |
if row[4] == user_id and row[5] == page_id and row[8].lower() == 'false':
|
| 94 |
history.append({
|
| 95 |
'conversation_id': row[0],
|
|
|
|
| 90 |
history = []
|
| 91 |
|
| 92 |
for row in values:
|
| 93 |
+
# Bổ sung cột rỗng cho đủ 9 cột
|
| 94 |
+
row = row + [""] * (9 - len(row))
|
| 95 |
if row[4] == user_id and row[5] == page_id and row[8].lower() == 'false':
|
| 96 |
history.append({
|
| 97 |
'conversation_id': row[0],
|
app/supabase_db.py
CHANGED
|
@@ -3,6 +3,7 @@ from supabase.client import create_client, Client
|
|
| 3 |
from loguru import logger
|
| 4 |
|
| 5 |
from .utils import timing_decorator_sync
|
|
|
|
| 6 |
|
| 7 |
class SupabaseClient:
|
| 8 |
def __init__(self, url: str, key: str):
|
|
@@ -30,10 +31,10 @@ class SupabaseClient:
|
|
| 30 |
return None
|
| 31 |
|
| 32 |
@timing_decorator_sync
|
| 33 |
-
def match_documents(self, embedding: List[float], match_count: int = 5,
|
| 34 |
"""
|
| 35 |
Truy vấn vector similarity search qua RPC match_documents.
|
| 36 |
-
Input: embedding (list[float]), match_count (int),
|
| 37 |
Output: list[dict] kết quả truy vấn.
|
| 38 |
"""
|
| 39 |
try:
|
|
@@ -42,8 +43,10 @@ class SupabaseClient:
|
|
| 42 |
'match_threshold': 0.7,
|
| 43 |
'match_count': match_count
|
| 44 |
}
|
| 45 |
-
if
|
| 46 |
-
|
|
|
|
|
|
|
| 47 |
response = self.client.rpc(
|
| 48 |
'match_documents',
|
| 49 |
payload
|
|
|
|
| 3 |
from loguru import logger
|
| 4 |
|
| 5 |
from .utils import timing_decorator_sync
|
| 6 |
+
from .constants import VEHICLE_KEYWORD_TO_COLUMN
|
| 7 |
|
| 8 |
class SupabaseClient:
|
| 9 |
def __init__(self, url: str, key: str):
|
|
|
|
| 31 |
return None
|
| 32 |
|
| 33 |
@timing_decorator_sync
|
| 34 |
+
def match_documents(self, embedding: List[float], match_count: int = 5, vehicle_keywords: Optional[List[str]] = None):
|
| 35 |
"""
|
| 36 |
Truy vấn vector similarity search qua RPC match_documents.
|
| 37 |
+
Input: embedding (list[float]), match_count (int), vehicle_keywords (list[str] hoặc None)
|
| 38 |
Output: list[dict] kết quả truy vấn.
|
| 39 |
"""
|
| 40 |
try:
|
|
|
|
| 43 |
'match_threshold': 0.7,
|
| 44 |
'match_count': match_count
|
| 45 |
}
|
| 46 |
+
if vehicle_keywords:
|
| 47 |
+
vehicle_columns = [VEHICLE_KEYWORD_TO_COLUMN[k] for k in vehicle_keywords if k in VEHICLE_KEYWORD_TO_COLUMN]
|
| 48 |
+
if vehicle_columns:
|
| 49 |
+
payload['vehicle_filters'] = vehicle_columns
|
| 50 |
response = self.client.rpc(
|
| 51 |
'match_documents',
|
| 52 |
payload
|