mickeywu520 commited on
Commit
85ef28f
·
1 Parent(s): 3887148

修正查詢

Browse files
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
- products = query.options(joinedload(Product.category)).limit(limit).all()
263
- logger.info(f"📦 查詢到 {len(products)} 個商品")
 
 
 
 
 
 
 
 
 
 
 
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()