feat: AI 기반 제품 카테고리 자동 태깅 및 UI 표시
- OpenAI GPT-4o-mini로 31개 제품 자동 분류 (100% 커버리지) - 관리자 페이지 사용자 상세 모달에 카테고리 뱃지 추가 - BARCODE 기반 제품-카테고리 매핑 (many-to-many) - 카테고리별 색상 구분 (10가지 그라디언트 디자인) - 제품 수동 분류 도구 추가 (update_product_category.py) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
107
backend/update_product_category.py
Normal file
107
backend/update_product_category.py
Normal file
@@ -0,0 +1,107 @@
|
||||
"""
|
||||
제품 카테고리 수동 업데이트
|
||||
"""
|
||||
|
||||
import sys
|
||||
import sqlite3
|
||||
import os
|
||||
|
||||
# UTF-8 인코딩 강제 (Windows 한글 깨짐 방지)
|
||||
if sys.platform == 'win32':
|
||||
import io
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||||
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')
|
||||
|
||||
|
||||
def update_category(product_name, category_name, relevance_score=1.0):
|
||||
"""제품 카테고리 업데이트"""
|
||||
db_path = os.path.join(os.path.dirname(__file__), 'db', 'mileage.db')
|
||||
conn = sqlite3.connect(db_path)
|
||||
cursor = conn.cursor()
|
||||
|
||||
try:
|
||||
# 제품 바코드 조회
|
||||
cursor.execute(
|
||||
"SELECT barcode FROM product_master WHERE product_name = ?",
|
||||
(product_name,)
|
||||
)
|
||||
result = cursor.fetchone()
|
||||
|
||||
if not result:
|
||||
print(f"[ERROR] '{product_name}' 제품을 찾을 수 없습니다.")
|
||||
return False
|
||||
|
||||
barcode = result[0]
|
||||
|
||||
# 카테고리 매핑 추가 (이미 있으면 업데이트)
|
||||
cursor.execute("""
|
||||
INSERT OR REPLACE INTO product_category_mapping
|
||||
(barcode, category_name, relevance_score)
|
||||
VALUES (?, ?, ?)
|
||||
""", (barcode, category_name, relevance_score))
|
||||
|
||||
conn.commit()
|
||||
print(f"[OK] '{product_name}' → '{category_name}' (관련도: {relevance_score})")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"[ERROR] {e}")
|
||||
conn.rollback()
|
||||
return False
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
def show_stats():
|
||||
"""제품 통계 조회"""
|
||||
db_path = os.path.join(os.path.dirname(__file__), 'db', 'mileage.db')
|
||||
conn = sqlite3.connect(db_path)
|
||||
cursor = conn.cursor()
|
||||
|
||||
try:
|
||||
# 전체 제품 수
|
||||
cursor.execute("SELECT COUNT(*) FROM product_master")
|
||||
total = cursor.fetchone()[0]
|
||||
|
||||
# 카테고리가 있는 제품 수
|
||||
cursor.execute("""
|
||||
SELECT COUNT(DISTINCT barcode)
|
||||
FROM product_category_mapping
|
||||
""")
|
||||
categorized = cursor.fetchone()[0]
|
||||
|
||||
# 카테고리가 없는 제품 수
|
||||
uncategorized = total - categorized
|
||||
|
||||
print("\n" + "="*80)
|
||||
print("제품 통계")
|
||||
print("="*80)
|
||||
print(f"전체 제품 수: {total}개")
|
||||
print(f"카테고리 있는 제품: {categorized}개")
|
||||
print(f"카테고리 없는 제품: {uncategorized}개")
|
||||
print("="*80)
|
||||
|
||||
# 카테고리별 제품 수
|
||||
cursor.execute("""
|
||||
SELECT category_name, COUNT(*) as count
|
||||
FROM product_category_mapping
|
||||
GROUP BY category_name
|
||||
ORDER BY count DESC
|
||||
""")
|
||||
print("\n카테고리별 제품 수:")
|
||||
for cat, count in cursor.fetchall():
|
||||
print(f" {cat:20} : {count:3}개")
|
||||
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("제품 카테고리 업데이트")
|
||||
print("="*80)
|
||||
|
||||
# 소하자임플러스정 → 소화제
|
||||
update_category("소하자임플러스정", "소화제", 1.0)
|
||||
|
||||
# 통계 출력
|
||||
show_stats()
|
||||
Reference in New Issue
Block a user