#!/usr/bin/env python3 """ BarkScan - 반려동물 사료 안전 분석기 HuggingFace Spaces Gradio App (2025) - 한글 버전 """ import gradio as gr import cv2 import numpy as np from pyzbar.pyzbar import decode import json from typing import Dict, List, Optional, Tuple import sqlite3 import os # 샘플 제품 데이터베이스 (시연용 인메모리) SAMPLE_PRODUCTS = { "8801234567890": { "name": "로얄캐닌 미니 어덜트", "brand": "로얄캐닌", "category": "강아지 사료", "ingredients": "쌀, 탈수가금육단백질, 동물성지방, 옥수수, 사탕무펄프, 가수분해 동물성 단백질", "protein": 27.0, "fat": 16.0, "fiber": 1.5, "safety_score": 85, "grade": "A", "harmful_substances": [] }, "8801234567898": { "name": "저가 강아지 사료", "brand": "일반 브랜드", "category": "강아지 사료", "ingredients": "옥수수가루, 육류부산물, BHA(보존제), 에톡시퀸, 인공색소", "protein": 18.0, "fat": 12.0, "fiber": 4.0, "safety_score": 45, "grade": "D", "harmful_substances": [ {"name": "BHA", "risk_level": "high", "description": "발암 가능 물질"}, {"name": "에톡시퀸", "risk_level": "high", "description": "살충제 성분 - 사람 음식에는 금지"} ] }, "8801234567899": { "name": "오리젠 오리지널 독", "brand": "오리젠", "category": "강아지 사료", "ingredients": "신선한 닭고기, 신선한 칠면조 고기, 신선한 계란, 신선한 닭 간", "protein": 38.0, "fat": 18.0, "fiber": 4.0, "safety_score": 95, "grade": "A+", "harmful_substances": [] } } # 유해 성분 데이터베이스 HARMFUL_SUBSTANCES = { "bha": {"name": "BHA", "risk": "high", "description": "부틸화 히드록시아니솔 - 발암 가능 물질"}, "bht": {"name": "BHT", "risk": "high", "description": "부틸화 히드록시톨루엔 - 간 손상 위험"}, "ethoxyquin": {"name": "에톡시퀸", "risk": "high", "description": "살충제 성분 보존료 - 사람 음식에는 금지"}, "에톡시퀸": {"name": "에톡시퀸", "risk": "high", "description": "살충제 성분 보존료 - 사람 음식에는 금지"}, "propylene glycol": {"name": "프로필렌 글리콜", "risk": "medium", "description": "고양이에게 빈혈 유발 가능"}, "artificial color": {"name": "인공색소", "risk": "medium", "description": "알레르기 반응 유발 가능"}, "인공색소": {"name": "인공색소", "risk": "medium", "description": "알레르기 반응 유발 가능"}, "corn syrup": {"name": "옥수수 시럽", "risk": "low", "description": "고당분 - 비만 위험"}, "by-product": {"name": "육류부산물", "risk": "medium", "description": "저품질 단백질"}, "부산물": {"name": "육류부산물", "risk": "medium", "description": "저품질 단백질"}, "carrageenan": {"name": "카라기난", "risk": "medium", "description": "소화기 염증 유발 가능"}, "cellulose": {"name": "셀룰로오스", "risk": "low", "description": "영양가 없는 충전재"}, "rendered fat": {"name": "렌더링 지방", "risk": "low", "description": "저품질 지방"} } def detect_barcode_from_image(image: np.ndarray) -> Optional[str]: """ 이미지에서 바코드 감지 (ZBar 사용) """ if image is None: return None # 그레이스케일 변환으로 인식률 향상 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 바코드 감지 및 디코딩 barcodes = decode(gray) if barcodes: # 첫 번째 바코드 반환 barcode_data = barcodes[0].data.decode('utf-8') return barcode_data return None def analyze_ingredients(ingredients: str) -> Tuple[List[Dict], int, str]: """ 성분 분석하여 유해 물질 감지 """ ingredients_lower = ingredients.lower() detected_harmful = [] for key, info in HARMFUL_SUBSTANCES.items(): if key in ingredients_lower: detected_harmful.append({ "name": info["name"], "risk_level": info["risk"], "description": info["description"] }) # 안전 점수 계산 (0-100) base_score = 100 for substance in detected_harmful: if substance["risk_level"] == "high": base_score -= 20 elif substance["risk_level"] == "medium": base_score -= 10 elif substance["risk_level"] == "low": base_score -= 5 safety_score = max(0, base_score) # 등급 계산 if safety_score >= 90: grade = "A+" elif safety_score >= 80: grade = "A" elif safety_score >= 70: grade = "B" elif safety_score >= 60: grade = "C" elif safety_score >= 50: grade = "D" else: grade = "F" return detected_harmful, safety_score, grade def get_product_info(barcode: str) -> Optional[Dict]: """ 데이터베이스에서 제품 정보 조회 """ return SAMPLE_PRODUCTS.get(barcode) def format_product_result(product: Dict) -> str: """ 제품 정보를 HTML로 포맷팅 """ # 등급별 색상 grade_colors = { "A+": "#00b300", "A": "#33cc33", "B": "#66cc00", "C": "#ffcc00", "D": "#ff9900", "F": "#ff3300" } grade = product.get("grade", "N/A") grade_color = grade_colors.get(grade, "#999999") html = f"""
제조사: {product['brand']}
안전 점수: {product['safety_score']}/100점
단백질: {product.get('protein', 'N/A')}%
지방: {product.get('fat', 'N/A')}%
섬유질: {product.get('fiber', 'N/A')}%
{product.get('ingredients', 'N/A')}
{substance['name']}
{substance.get('description', '')}
데이터베이스 기준 안전한 제품입니다.
다음을 시도해보세요:
바코드 {barcode}가 데이터베이스에 없습니다.
테스트용 샘플 바코드를 사용해보세요: