Commit
·
85ef28f
1
Parent(s):
3887148
修正查詢
Browse files- backend/services/enhanced_product_service.py +34 -3
- debug_sql_query.py +195 -0
- test_database_connection.py +211 -0
backend/services/enhanced_product_service.py
CHANGED
@@ -227,6 +227,14 @@ class EnhancedProductService:
|
|
227 |
|
228 |
logger.info(f"✅ 資料庫連接成功")
|
229 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
230 |
# 分析查詢關鍵字
|
231 |
keywords = self._extract_keywords(query_text)
|
232 |
logger.info(f"🔑 推薦查詢關鍵字: {keywords}")
|
@@ -246,11 +254,20 @@ class EnhancedProductService:
|
|
246 |
])
|
247 |
|
248 |
logger.info(f"🔍 建立了 {len(search_filters)} 個搜尋條件")
|
|
|
249 |
|
250 |
# 使用 OR 連接所有搜尋條件
|
251 |
if search_filters:
|
252 |
query = query.filter(or_(*search_filters))
|
253 |
-
logger.info(f"✅
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
254 |
else:
|
255 |
logger.warning(f"⚠️ 沒有搜尋條件")
|
256 |
else:
|
@@ -259,8 +276,19 @@ class EnhancedProductService:
|
|
259 |
# 優先顯示有庫存的商品
|
260 |
query = query.order_by(Product.stock.desc())
|
261 |
|
262 |
-
|
263 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
264 |
|
265 |
data = []
|
266 |
for product in products:
|
@@ -303,7 +331,10 @@ class EnhancedProductService:
|
|
303 |
)
|
304 |
finally:
|
305 |
if db:
|
|
|
306 |
close_database_session(db)
|
|
|
|
|
307 |
|
308 |
def _get_stock_status(self, stock: int) -> str:
|
309 |
"""獲取庫存狀態"""
|
|
|
227 |
|
228 |
logger.info(f"✅ 資料庫連接成功")
|
229 |
|
230 |
+
# 測試基本查詢
|
231 |
+
try:
|
232 |
+
total_products = db.query(Product).filter(Product.is_deleted == False).count()
|
233 |
+
logger.info(f"📊 資料庫中共有 {total_products} 個有效商品")
|
234 |
+
except Exception as e:
|
235 |
+
logger.error(f"❌ 基本查詢失敗: {str(e)}")
|
236 |
+
return DatabaseResult(success=False, error=f"基本查詢失敗: {str(e)}")
|
237 |
+
|
238 |
# 分析查詢關鍵字
|
239 |
keywords = self._extract_keywords(query_text)
|
240 |
logger.info(f"🔑 推薦查詢關鍵字: {keywords}")
|
|
|
254 |
])
|
255 |
|
256 |
logger.info(f"🔍 建立了 {len(search_filters)} 個搜尋條件")
|
257 |
+
logger.info(f"🔑 前5個搜尋條件: {[f'productName ILIKE %{kw}%' for kw in keywords[:5]]}")
|
258 |
|
259 |
# 使用 OR 連接所有搜尋條件
|
260 |
if search_filters:
|
261 |
query = query.filter(or_(*search_filters))
|
262 |
+
logger.info(f"✅ 搜尋條件已應用到查詢")
|
263 |
+
|
264 |
+
# 測試查詢執行
|
265 |
+
try:
|
266 |
+
test_count = query.count()
|
267 |
+
logger.info(f"📊 符合條件的商品數量: {test_count}")
|
268 |
+
except Exception as e:
|
269 |
+
logger.error(f"❌ 查詢計數失敗: {str(e)}")
|
270 |
+
return DatabaseResult(success=False, error=f"查詢執行失敗: {str(e)}")
|
271 |
else:
|
272 |
logger.warning(f"⚠️ 沒有搜尋條件")
|
273 |
else:
|
|
|
276 |
# 優先顯示有庫存的商品
|
277 |
query = query.order_by(Product.stock.desc())
|
278 |
|
279 |
+
try:
|
280 |
+
products = query.options(joinedload(Product.category)).limit(limit).all()
|
281 |
+
logger.info(f"📦 成功查詢到 {len(products)} 個商品")
|
282 |
+
|
283 |
+
# 記錄每個商品的詳細資訊
|
284 |
+
for product in products:
|
285 |
+
logger.info(f"📦 商品詳情: {product.productName} (編號: {product.productCode}, 庫存: {product.stock})")
|
286 |
+
|
287 |
+
except Exception as e:
|
288 |
+
logger.error(f"❌ 商品查詢執行失敗: {str(e)}")
|
289 |
+
import traceback
|
290 |
+
logger.error(f"📋 查詢錯誤詳情: {traceback.format_exc()}")
|
291 |
+
return DatabaseResult(success=False, error=f"商品查詢執行失敗: {str(e)}")
|
292 |
|
293 |
data = []
|
294 |
for product in products:
|
|
|
331 |
)
|
332 |
finally:
|
333 |
if db:
|
334 |
+
logger.info(f"🔒 關閉資料庫連接")
|
335 |
close_database_session(db)
|
336 |
+
else:
|
337 |
+
logger.warning(f"⚠️ 沒有資料庫連接需要關閉")
|
338 |
|
339 |
def _get_stock_status(self, stock: int) -> str:
|
340 |
"""獲取庫存狀態"""
|
debug_sql_query.py
ADDED
@@ -0,0 +1,195 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
調試 SQL 查詢 - 檢查實際執行的 SQL
|
3 |
+
"""
|
4 |
+
|
5 |
+
def debug_sql_query():
|
6 |
+
"""調試 SQL 查詢邏輯"""
|
7 |
+
|
8 |
+
print("🔍 調試 SQL 查詢邏輯")
|
9 |
+
print("=" * 50)
|
10 |
+
|
11 |
+
# 模擬關鍵字
|
12 |
+
keywords = ['貓砂', '礦砂', '豆腐砂', '水晶砂', '木屑砂', 'litter', '貓']
|
13 |
+
|
14 |
+
print(f"關鍵字: {keywords}")
|
15 |
+
|
16 |
+
# 生成 SQL 查詢條件
|
17 |
+
search_conditions = []
|
18 |
+
|
19 |
+
for keyword in keywords:
|
20 |
+
search_conditions.extend([
|
21 |
+
f"productName ILIKE '%{keyword}%'",
|
22 |
+
f"productCode ILIKE '%{keyword}%'",
|
23 |
+
f"barcode ILIKE '%{keyword}%'"
|
24 |
+
])
|
25 |
+
|
26 |
+
print(f"\n生成的搜尋條件數量: {len(search_conditions)}")
|
27 |
+
print("前10個條件:")
|
28 |
+
for i, condition in enumerate(search_conditions[:10], 1):
|
29 |
+
print(f" {i}. {condition}")
|
30 |
+
|
31 |
+
# 組合完整的 SQL
|
32 |
+
where_clause = " OR ".join(search_conditions)
|
33 |
+
full_sql = f"""
|
34 |
+
SELECT id, productCode, productName, stock, warehouse, category_id
|
35 |
+
FROM products
|
36 |
+
WHERE is_deleted = false
|
37 |
+
AND ({where_clause})
|
38 |
+
ORDER BY stock DESC
|
39 |
+
LIMIT 5;
|
40 |
+
"""
|
41 |
+
|
42 |
+
print(f"\n完整 SQL 查詢:")
|
43 |
+
print(full_sql)
|
44 |
+
|
45 |
+
# 測試與實際商品的匹配
|
46 |
+
print(f"\n🛍️ 測試與實際商品的匹配")
|
47 |
+
print("=" * 50)
|
48 |
+
|
49 |
+
# 實際商品資料
|
50 |
+
products = [
|
51 |
+
{
|
52 |
+
"id": 1,
|
53 |
+
"productCode": "OL1100-1",
|
54 |
+
"productName": "毆力天然犬種300g 室內成犬無榖小顆粒",
|
55 |
+
"stock": 100
|
56 |
+
},
|
57 |
+
{
|
58 |
+
"id": 2,
|
59 |
+
"productCode": "SW-06-01",
|
60 |
+
"productName": "Shovel well豪好鏟 破碎型礦砂",
|
61 |
+
"stock": 50
|
62 |
+
},
|
63 |
+
{
|
64 |
+
"id": 3,
|
65 |
+
"productCode": "TL-03",
|
66 |
+
"productName": "美國極冠貓砂 薰衣草12kg",
|
67 |
+
"stock": 48
|
68 |
+
},
|
69 |
+
{
|
70 |
+
"id": 4,
|
71 |
+
"productCode": "SL11002",
|
72 |
+
"productName": "首領汪 膠原鴨舌 5入彭湃包",
|
73 |
+
"stock": 100
|
74 |
+
}
|
75 |
+
]
|
76 |
+
|
77 |
+
matched_products = []
|
78 |
+
|
79 |
+
for product in products:
|
80 |
+
product_name = product["productName"].lower()
|
81 |
+
product_code = product["productCode"].lower()
|
82 |
+
|
83 |
+
# 檢查是否匹配任一關鍵字
|
84 |
+
for keyword in keywords:
|
85 |
+
keyword_lower = keyword.lower()
|
86 |
+
|
87 |
+
if (keyword_lower in product_name or
|
88 |
+
keyword_lower in product_code):
|
89 |
+
matched_products.append({
|
90 |
+
"product": product,
|
91 |
+
"matched_keyword": keyword
|
92 |
+
})
|
93 |
+
print(f"✅ 匹配: {product['productName']} (關鍵字: '{keyword}')")
|
94 |
+
break
|
95 |
+
|
96 |
+
print(f"\n總共匹配 {len(matched_products)} 個商品")
|
97 |
+
|
98 |
+
if not matched_products:
|
99 |
+
print("❌ 沒有匹配的商品")
|
100 |
+
|
101 |
+
# 逐個測試關鍵字
|
102 |
+
print("\n🔍 逐個測試關鍵字:")
|
103 |
+
for keyword in keywords:
|
104 |
+
print(f"\n關鍵字: '{keyword}'")
|
105 |
+
found = False
|
106 |
+
for product in products:
|
107 |
+
if keyword.lower() in product["productName"].lower():
|
108 |
+
print(f" ✅ 匹配商品: {product['productName']}")
|
109 |
+
found = True
|
110 |
+
if not found:
|
111 |
+
print(f" ❌ 無匹配商品")
|
112 |
+
|
113 |
+
def debug_ilike_logic():
|
114 |
+
"""調試 ILIKE 邏輯"""
|
115 |
+
|
116 |
+
print(f"\n🔍 調試 ILIKE 邏輯")
|
117 |
+
print("=" * 50)
|
118 |
+
|
119 |
+
# 測試字串
|
120 |
+
test_strings = [
|
121 |
+
"美國極冠貓砂 薰衣草12kg",
|
122 |
+
"Shovel well豪好鏟 破碎型礦砂",
|
123 |
+
"毆力天然犬種300g 室內成犬無榖小顆粒",
|
124 |
+
"首領汪 膠原鴨舌 5入彭湃包"
|
125 |
+
]
|
126 |
+
|
127 |
+
# 測試關鍵字
|
128 |
+
test_keywords = ["貓砂", "礦砂", "貓", "狗", "犬"]
|
129 |
+
|
130 |
+
print("ILIKE 匹配測試:")
|
131 |
+
for keyword in test_keywords:
|
132 |
+
print(f"\n關鍵字: '{keyword}'")
|
133 |
+
for string in test_strings:
|
134 |
+
# 模擬 ILIKE '%keyword%' 邏輯
|
135 |
+
if keyword.lower() in string.lower():
|
136 |
+
print(f" ✅ '{string}' 包含 '{keyword}'")
|
137 |
+
else:
|
138 |
+
print(f" ❌ '{string}' 不包含 '{keyword}'")
|
139 |
+
|
140 |
+
def debug_or_logic():
|
141 |
+
"""調試 OR 邏輯"""
|
142 |
+
|
143 |
+
print(f"\n🔍 調試 OR 邏輯")
|
144 |
+
print("=" * 50)
|
145 |
+
|
146 |
+
# 模擬 SQLAlchemy OR 查詢
|
147 |
+
products = [
|
148 |
+
{"productName": "美國極冠貓砂 薰衣草12kg", "productCode": "TL-03"},
|
149 |
+
{"productName": "Shovel well豪好鏟 破碎型礦砂", "productCode": "SW-06-01"},
|
150 |
+
{"productName": "毆力天然犬種300g 室內成犬無榖小顆粒", "productCode": "OL1100-1"},
|
151 |
+
{"productName": "首領汪 膠原鴨舌 5入彭湃包", "productCode": "SL11002"}
|
152 |
+
]
|
153 |
+
|
154 |
+
keywords = ['貓砂', '礦砂']
|
155 |
+
|
156 |
+
print(f"使用關鍵字: {keywords}")
|
157 |
+
print("OR 邏輯測試:")
|
158 |
+
|
159 |
+
for product in products:
|
160 |
+
conditions_met = []
|
161 |
+
|
162 |
+
for keyword in keywords:
|
163 |
+
# 檢查 productName
|
164 |
+
if keyword.lower() in product["productName"].lower():
|
165 |
+
conditions_met.append(f"productName contains '{keyword}'")
|
166 |
+
|
167 |
+
# 檢查 productCode
|
168 |
+
if keyword.lower() in product["productCode"].lower():
|
169 |
+
conditions_met.append(f"productCode contains '{keyword}'")
|
170 |
+
|
171 |
+
if conditions_met:
|
172 |
+
print(f" ✅ {product['productName']}")
|
173 |
+
print(f" 滿足條件: {', '.join(conditions_met)}")
|
174 |
+
else:
|
175 |
+
print(f" ❌ {product['productName']} (無匹配)")
|
176 |
+
|
177 |
+
def main():
|
178 |
+
"""主函數"""
|
179 |
+
print("🚀 開始 SQL 查詢調試")
|
180 |
+
print("=" * 60)
|
181 |
+
|
182 |
+
debug_sql_query()
|
183 |
+
debug_ilike_logic()
|
184 |
+
debug_or_logic()
|
185 |
+
|
186 |
+
print("\n" + "=" * 60)
|
187 |
+
print("✅ SQL 調試完成!")
|
188 |
+
print("\n💡 如果邏輯測試都正確,問題可能在於:")
|
189 |
+
print("1. 資料庫連接問題")
|
190 |
+
print("2. SQLAlchemy 查詢執行問題")
|
191 |
+
print("3. 事務或會話問題")
|
192 |
+
print("4. 權限問題")
|
193 |
+
|
194 |
+
if __name__ == "__main__":
|
195 |
+
main()
|
test_database_connection.py
ADDED
@@ -0,0 +1,211 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
測試資料庫連接和商品查詢
|
3 |
+
"""
|
4 |
+
|
5 |
+
import sys
|
6 |
+
import os
|
7 |
+
|
8 |
+
# 添加專案根目錄到 Python 路徑
|
9 |
+
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
10 |
+
|
11 |
+
def test_database_connection():
|
12 |
+
"""測試資料庫連接"""
|
13 |
+
try:
|
14 |
+
from backend.database.connection import get_database_session, close_database_session
|
15 |
+
from backend.database.models import Product, Category
|
16 |
+
from sqlalchemy.orm import joinedload
|
17 |
+
from sqlalchemy import text
|
18 |
+
|
19 |
+
print("🔗 測試資料庫連接...")
|
20 |
+
db = get_database_session()
|
21 |
+
|
22 |
+
if not db:
|
23 |
+
print("❌ 無法獲取資料庫連接")
|
24 |
+
return False
|
25 |
+
|
26 |
+
print("✅ 資料庫連接成功")
|
27 |
+
|
28 |
+
# 1. 測試原始 SQL 查詢
|
29 |
+
print("\n1. 測試原始 SQL 查詢...")
|
30 |
+
try:
|
31 |
+
result = db.execute(text("SELECT COUNT(*) as count FROM products WHERE is_deleted = false"))
|
32 |
+
count = result.fetchone()[0]
|
33 |
+
print(f" 商品總數 (SQL): {count}")
|
34 |
+
except Exception as e:
|
35 |
+
print(f" ❌ SQL 查詢失敗: {str(e)}")
|
36 |
+
return False
|
37 |
+
|
38 |
+
# 2. 測試 ORM 查詢
|
39 |
+
print("\n2. 測試 ORM 查詢...")
|
40 |
+
try:
|
41 |
+
products = db.query(Product).filter(Product.is_deleted == False).all()
|
42 |
+
print(f" 商品總數 (ORM): {len(products)}")
|
43 |
+
|
44 |
+
if products:
|
45 |
+
print(" 前3個商品:")
|
46 |
+
for i, product in enumerate(products[:3], 1):
|
47 |
+
print(f" {i}. {product.productName} (編號: {product.productCode}, 庫存: {product.stock})")
|
48 |
+
|
49 |
+
except Exception as e:
|
50 |
+
print(f" ❌ ORM 查詢失敗: {str(e)}")
|
51 |
+
import traceback
|
52 |
+
traceback.print_exc()
|
53 |
+
return False
|
54 |
+
|
55 |
+
# 3. 測試關聯查詢
|
56 |
+
print("\n3. 測試關聯查詢...")
|
57 |
+
try:
|
58 |
+
products_with_category = db.query(Product).options(
|
59 |
+
joinedload(Product.category)
|
60 |
+
).filter(Product.is_deleted == False).limit(3).all()
|
61 |
+
|
62 |
+
print(f" 關聯查詢成功,取得 {len(products_with_category)} 個商品")
|
63 |
+
for product in products_with_category:
|
64 |
+
category_name = product.category.name if product.category else "無分類"
|
65 |
+
print(f" - {product.productName} (分類: {category_name})")
|
66 |
+
|
67 |
+
except Exception as e:
|
68 |
+
print(f" ❌ 關聯查詢失敗: {str(e)}")
|
69 |
+
import traceback
|
70 |
+
traceback.print_exc()
|
71 |
+
return False
|
72 |
+
|
73 |
+
# 4. 測試貓砂相關商品查詢
|
74 |
+
print("\n4. 測試貓砂相關商品查詢...")
|
75 |
+
try:
|
76 |
+
from sqlalchemy import or_
|
77 |
+
|
78 |
+
keywords = ['貓砂', '礦砂', '貓']
|
79 |
+
search_filters = []
|
80 |
+
|
81 |
+
for keyword in keywords:
|
82 |
+
search_filters.extend([
|
83 |
+
Product.productName.ilike(f"%{keyword}%"),
|
84 |
+
Product.productCode.ilike(f"%{keyword}%")
|
85 |
+
])
|
86 |
+
|
87 |
+
cat_products = db.query(Product).filter(
|
88 |
+
Product.is_deleted == False
|
89 |
+
).filter(
|
90 |
+
or_(*search_filters)
|
91 |
+
).all()
|
92 |
+
|
93 |
+
print(f" 找到 {len(cat_products)} 個貓砂相關商品:")
|
94 |
+
for product in cat_products:
|
95 |
+
print(f" ✅ {product.productName} (庫存: {product.stock})")
|
96 |
+
|
97 |
+
except Exception as e:
|
98 |
+
print(f" ❌ 貓砂查詢失敗: {str(e)}")
|
99 |
+
import traceback
|
100 |
+
traceback.print_exc()
|
101 |
+
return False
|
102 |
+
|
103 |
+
close_database_session(db)
|
104 |
+
return True
|
105 |
+
|
106 |
+
except Exception as e:
|
107 |
+
print(f"❌ 資料庫測試失敗: {str(e)}")
|
108 |
+
import traceback
|
109 |
+
traceback.print_exc()
|
110 |
+
return False
|
111 |
+
|
112 |
+
def test_enhanced_product_service():
|
113 |
+
"""測試 Enhanced Product Service"""
|
114 |
+
try:
|
115 |
+
from backend.services.enhanced_product_service import EnhancedProductService
|
116 |
+
|
117 |
+
print("\n🛍️ 測試 Enhanced Product Service...")
|
118 |
+
|
119 |
+
service = EnhancedProductService()
|
120 |
+
|
121 |
+
# 測試推薦查詢
|
122 |
+
print("\n測試推薦查詢: '貓砂還有嗎?'")
|
123 |
+
result = service.get_product_recommendations(
|
124 |
+
query_text="貓砂還有嗎?",
|
125 |
+
limit=5
|
126 |
+
)
|
127 |
+
|
128 |
+
print(f"查詢結果:")
|
129 |
+
print(f" 成功: {result.success}")
|
130 |
+
print(f" 數量: {result.count}")
|
131 |
+
print(f" 錯誤: {result.error}")
|
132 |
+
|
133 |
+
if result.success and result.data:
|
134 |
+
print(f" 找到的商品:")
|
135 |
+
for item in result.data:
|
136 |
+
print(f" - {item.get('product_name')} (庫存: {item.get('current_stock')})")
|
137 |
+
|
138 |
+
return result.success
|
139 |
+
|
140 |
+
except Exception as e:
|
141 |
+
print(f"��� Enhanced Product Service 測試失敗: {str(e)}")
|
142 |
+
import traceback
|
143 |
+
traceback.print_exc()
|
144 |
+
return False
|
145 |
+
|
146 |
+
def test_pydantic_ai_service():
|
147 |
+
"""測試 Pydantic AI Service"""
|
148 |
+
try:
|
149 |
+
from backend.services.pydantic_ai_service import ProductQueryService
|
150 |
+
|
151 |
+
print("\n🤖 測試 Pydantic AI Service...")
|
152 |
+
|
153 |
+
service = ProductQueryService()
|
154 |
+
|
155 |
+
if not service.is_available():
|
156 |
+
print("⚠️ Pydantic AI 服務不可用 (可能缺少 GROQ_API_KEY)")
|
157 |
+
return False
|
158 |
+
|
159 |
+
# 測試同步查詢
|
160 |
+
print("\n測試同步查詢: '貓砂還有嗎?'")
|
161 |
+
result = service.process_product_query_sync(
|
162 |
+
user_message="貓砂還有嗎?",
|
163 |
+
user_id="test_user"
|
164 |
+
)
|
165 |
+
|
166 |
+
print(f"查詢結果:")
|
167 |
+
print(f" 成功: {result.get('success')}")
|
168 |
+
print(f" 模式: {result.get('mode')}")
|
169 |
+
print(f" 錯誤: {result.get('error')}")
|
170 |
+
print(f" 回應: {result.get('text', '')[:100]}...")
|
171 |
+
|
172 |
+
return result.get('success', False)
|
173 |
+
|
174 |
+
except Exception as e:
|
175 |
+
print(f"❌ Pydantic AI Service 測試失敗: {str(e)}")
|
176 |
+
import traceback
|
177 |
+
traceback.print_exc()
|
178 |
+
return False
|
179 |
+
|
180 |
+
def main():
|
181 |
+
"""主函數"""
|
182 |
+
print("🚀 開始資料庫連接和服務測試")
|
183 |
+
print("=" * 60)
|
184 |
+
|
185 |
+
# 1. 測試資料庫連接
|
186 |
+
db_success = test_database_connection()
|
187 |
+
|
188 |
+
if not db_success:
|
189 |
+
print("\n❌ 資料庫連接測試失敗,停止後續測試")
|
190 |
+
return
|
191 |
+
|
192 |
+
# 2. 測試 Enhanced Product Service
|
193 |
+
service_success = test_enhanced_product_service()
|
194 |
+
|
195 |
+
# 3. 測試 Pydantic AI Service
|
196 |
+
ai_success = test_pydantic_ai_service()
|
197 |
+
|
198 |
+
print("\n" + "=" * 60)
|
199 |
+
print("📊 測試結果總結:")
|
200 |
+
print(f" 資料庫連接: {'✅ 成功' if db_success else '❌ 失敗'}")
|
201 |
+
print(f" Enhanced Product Service: {'✅ 成功' if service_success else '❌ 失敗'}")
|
202 |
+
print(f" Pydantic AI Service: {'✅ 成功' if ai_success else '❌ 失敗'}")
|
203 |
+
|
204 |
+
if db_success and service_success:
|
205 |
+
print("\n💡 如果服務測試成功但 LineBot 仍然沒有回應,問題可能在於:")
|
206 |
+
print(" 1. LineBot 路由邏輯")
|
207 |
+
print(" 2. 回應格式化")
|
208 |
+
print(" 3. LINE API 回應")
|
209 |
+
|
210 |
+
if __name__ == "__main__":
|
211 |
+
main()
|