#!/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['name']}

제조사: {product['brand']}

{grade} 등급

안전 점수: {product['safety_score']}/100점

📊 영양 성분

단백질: {product.get('protein', 'N/A')}%

지방: {product.get('fat', 'N/A')}%

섬유질: {product.get('fiber', 'N/A')}%

🌾 원재료

{product.get('ingredients', 'N/A')}

""" # 유해 성분 섹션 if product.get("harmful_substances"): html += """

⚠️ 검출된 유해 성분

""" for substance in product["harmful_substances"]: risk_color = { "high": "#ff3300", "medium": "#ff9900", "low": "#ffcc00" }.get(substance.get("risk_level", "low"), "#999999") html += f"""

{substance['name']}

{substance.get('description', '')}

""" html += "
" else: html += """

✓ 유해 성분 미검출

데이터베이스 기준 안전한 제품입니다.

""" html += "
" return html def scan_and_analyze(image) -> Tuple[str, str]: """ 메인 함수: 바코드 스캔 후 제품 분석 """ if image is None: return "이미지가 제공되지 않았습니다", "이미지를 업로드하거나 카메라를 사용해주세요" # 바코드 감지 barcode = detect_barcode_from_image(image) if not barcode: return "❌ 바코드를 찾을 수 없습니다", """

바코드 인식 실패

다음을 시도해보세요:

""" barcode_result = f"✓ 바코드 인식: {barcode}" # 제품 정보 조회 product = get_product_info(barcode) if not product: return barcode_result, f"""

제품을 찾을 수 없습니다

바코드 {barcode}가 데이터베이스에 없습니다.

테스트용 샘플 바코드를 사용해보세요:

""" # 결과 포맷팅 및 반환 product_html = format_product_result(product) return barcode_result, product_html # Gradio 인터페이스 생성 def create_interface(): """Gradio 인터페이스 생성 및 설정""" with gr.Blocks(title="BarkScan - 반려동물 사료 안전 분석기", theme=gr.themes.Soft()) as app: gr.Markdown(""" # 🐾 BarkScan - 반려동물 사료 안전 분석기 **바코드를 스캔하여 사료 성분의 안전성을 확인하세요!** 바코드 사진을 업로드하거나 카메라를 사용하세요 (모바일에서는 후면 카메라가 자동으로 사용됩니다). """) with gr.Row(): with gr.Column(): image_input = gr.Image( sources=["upload", "webcam"], type="numpy", label="바코드 이미지 업로드 또는 카메라 촬영" ) scan_button = gr.Button("🔍 스캔 및 분석", variant="primary", size="lg") gr.Markdown(""" ### 테스트용 샘플 바코드: - **8801234567890** - 로얄캐닌 미니 어덜트 (A등급) - **8801234567898** - 저가 강아지 사료 (D등급 - ⚠️ BHA 포함) - **8801234567899** - 오리젠 오리지널 (A+등급) *테스트를 위해 이 바코드를 텍스트로 이미지에 입력할 수 있습니다* """) with gr.Column(): barcode_output = gr.Textbox(label="인식된 바코드", lines=1) analysis_output = gr.HTML(label="제품 분석 결과") scan_button.click( fn=scan_and_analyze, inputs=[image_input], outputs=[barcode_output, analysis_output] ) gr.Markdown(""" --- ### BarkScan 소개 BarkScan은 반려동물 사료 성분을 분석하여 다음과 같은 유해 물질을 감지합니다: - **BHA/BHT** (보존제 - 발암 가능 물질) - **에톡시퀸** (살충제 - 사람 음식에는 금지) - **인공색소** (알레르기 반응 유발 가능) - **프로필렌 글리콜** (고양이에게 독성) - **저품질 성분** (부산물, 충전재) **안전 등급 시스템:** - **A+** (90-100점): 최우수 - 프리미엄 품질 - **A** (80-89점): 우수 - 높은 품질, 약간의 우려 - **B** (70-79점): 양호 - 수용 가능한 품질 - **C** (60-69점): 보통 - 일부 우려사항 - **D** (50-59점): 미흡 - 다수의 유해 성분 - **F** (0-49점): 매우 미흡 - 피해야 함 --- **데이터 출처:** Open Pet Food Facts, 식품안전나라 **버전:** 1.0 (2025) | **반려동물 안전을 위해 ❤️** """) return app # 앱 실행 if __name__ == "__main__": app = create_interface() app.launch()