Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import cv2 | |
| import numpy as np | |
| import pandas as pd | |
| import json | |
| import os | |
| import threading | |
| import gc | |
| from datetime import datetime | |
| try: | |
| from pyngrok import ngrok | |
| NGROK_AVAILABLE = True | |
| except ImportError: | |
| NGROK_AVAILABLE = False | |
| try: | |
| from skimage.metrics import structural_similarity as ssim | |
| from skimage.metrics import peak_signal_noise_ratio as psnr | |
| except ImportError: | |
| # scikit-image๊ฐ ์๋ ๊ฒฝ์ฐ ๋์ฒด ๋ฐฉ๋ฒ ์ฌ์ฉ | |
| def ssim(img1, img2): | |
| # ๊ฐ๋จํ MSE ๊ธฐ๋ฐ ์ ์ฌ๋ ๊ณ์ฐ | |
| mse = np.mean((img1 - img2) ** 2) | |
| return 1 / (1 + mse / 1000) | |
| def psnr(img1, img2): | |
| mse = np.mean((img1 - img2) ** 2) | |
| if mse == 0: | |
| return 100 | |
| return 20 * np.log10(255.0 / np.sqrt(mse)) | |
| import io | |
| from PIL import Image | |
| import torch | |
| import torchvision.models as models | |
| import torchvision.transforms as transforms | |
| import ssl | |
| # Fix SSL error for model download (macOS specific) | |
| ssl._create_default_https_context = ssl._create_unverified_context | |
| # ========== ์ฌ๊ธฐ๋ง ์์ ํ๋ฉด ํญ์ด ๋์ ์ผ๋ก ๋ฐ์๋ฉ๋๋ค ========== | |
| # ์์: ["Response๋ฐ", "Challenge๋ฐ"] โ ์ฐ์ต ํญ + 2๊ฐ ๋ฐ = ์ด 3๊ฐ ํญ | |
| # ์์: ["206ํธ", "207ํธ", "305ํธ"] โ ์ฐ์ต ํญ + 3๊ฐ ๋ฐ = ์ด 4๊ฐ ํญ | |
| # CLASSES = ["Respect๋ฐ", "Challenge๋ฐ", "Originality๋ฐ", "BCE๋ฐ"] | |
| CLASSES = ["Respect๋ฐ", "Challenge๋ฐ", "Originality๋ฐ", "BCE๋ฐ"] | |
| # ============================================================ | |
| # ํญ ์์ด์ฝ ์๋ ๋ฐฐ์ | |
| _TAB_ICONS = ["๐ฏ", "โก", "๐จ", "๐ฅ", "๐", "๐", "๐", "๐ก", "๐ ", "โจ"] | |
| def _class_key(name): | |
| """๋ฐ ์ด๋ฆ์ json ํ์ผ๋ช /๋์ ๋๋ฆฌ ํค๋ก ๋ณํ (์: 'Respect๋ฐ' โ 'respect')""" | |
| # ํ๊ธ '๋ฐ' ์ ๊ฑฐ, ๊ณต๋ฐฑโ์ธ๋์ค์ฝ์ด, ์๋ฌธ์ | |
| return name.replace("๋ฐ", "").replace("ํธ", "").strip().lower().replace(" ", "_") | |
| class ImageSimilarityLeaderboard: | |
| def __init__(self, reference_image_path="label2.jpg", data_file="leaderboard.json"): | |
| self.reference_image_path = reference_image_path | |
| self.data_file = data_file | |
| self.admin_password = "9900" # ๊ด๋ฆฌ์ ๋น๋ฐ๋ฒํธ | |
| self.admin_authenticated = False # ๊ด๋ฆฌ์ ์ธ์ฆ ์ํ | |
| # ๋ฉ๋ชจ๋ฆฌ ์ต์ ํ๋ฅผ ์ํ ์บ์ ๋ฐ ๋ฝ (๋จผ์ ์ด๊ธฐํ) | |
| self._ref_image_cache = None | |
| self._ref_embedding = None # ResNet ์๋ฒ ๋ฉ ์บ์ | |
| self._cache_loaded = False | |
| self._file_lock = threading.Lock() # ํ์ผ I/O ๋์์ฑ ์ ์ด | |
| self._processing_lock = threading.Lock() # ์ฒ๋ฆฌ ๋์์ฑ ์ ์ด | |
| # ๋ฝ ์ด๊ธฐํ ํ ๋ฐ์ดํฐ ๋ก๋ | |
| self.leaderboard_data = self.load_leaderboard() | |
| self.last_modified = self.get_file_modified_time() | |
| # ResNet ๋ชจ๋ธ ์ด๊ธฐํ (ํ ๋ฒ๋ง ๋ก๋) | |
| self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu") | |
| try: | |
| # ResNet50 (ImageNet weights) - ๋ง์ง๋ง FC ๋ ์ด์ด ์ ์ธ | |
| resnet = models.resnet50(weights=models.ResNet50_Weights.IMAGENET1K_V1) | |
| self.resnet_model = torch.nn.Sequential(*(list(resnet.children())[:-1])).to(self.device) | |
| self.resnet_model.eval() | |
| # ์ ์ฒ๋ฆฌ ํ์ดํ๋ผ์ธ | |
| self.preprocess = transforms.Compose([ | |
| transforms.Resize(256), | |
| transforms.CenterCrop(224), | |
| transforms.ToTensor(), | |
| transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), | |
| ]) | |
| print(f"โ ResNet ๋ชจ๋ธ ๋ก๋ ์๋ฃ (Device: {self.device})") | |
| except Exception as e: | |
| print(f"โ ๏ธ ResNet ๋ชจ๋ธ ๋ก๋ ์คํจ: {e}") | |
| self.resnet_model = None | |
| # macOS ํธํ์ฑ์ ์ํ ๊ฒฝ๊ณ ์ต์ | |
| import warnings | |
| warnings.filterwarnings("ignore", category=UserWarning, module="cv2") | |
| def load_leaderboard(self): | |
| """๋ฆฌ๋๋ณด๋ ๋ฐ์ดํฐ๋ฅผ ๋ก๋ํฉ๋๋ค.""" | |
| with self._file_lock: # ํ์ผ I/O ๋์์ฑ ์ ์ด | |
| if os.path.exists(self.data_file): | |
| try: | |
| with open(self.data_file, 'r', encoding='utf-8') as f: | |
| return json.load(f) | |
| except: | |
| return [] | |
| return [] | |
| def get_file_modified_time(self): | |
| """ํ์ผ ์์ ์๊ฐ์ ๋ฐํํฉ๋๋ค.""" | |
| if os.path.exists(self.data_file): | |
| return os.path.getmtime(self.data_file) | |
| return 0 | |
| def save_leaderboard(self): | |
| """๋ฆฌ๋๋ณด๋ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํฉ๋๋ค.""" | |
| with self._file_lock: # ํ์ผ I/O ๋์์ฑ ์ ์ด | |
| with open(self.data_file, 'w', encoding='utf-8') as f: | |
| json.dump(self.leaderboard_data, f, ensure_ascii=False, indent=2) | |
| self.last_modified = self.get_file_modified_time() | |
| def check_for_updates(self): | |
| """๋ฆฌ๋๋ณด๋ ์ ๋ฐ์ดํธ ํ์ธ""" | |
| current_modified = self.get_file_modified_time() | |
| if current_modified > self.last_modified: | |
| self.leaderboard_data = self.load_leaderboard() | |
| self.last_modified = current_modified | |
| return True | |
| return False | |
| def _load_reference_image(self): | |
| """์ฐธ์กฐ ์ด๋ฏธ์ง๋ฅผ ํ ๋ฒ๋ง ๋ก๋ํ๊ณ ์บ์ํฉ๋๋ค.""" | |
| if not self._cache_loaded: | |
| if os.path.exists(self.reference_image_path): | |
| ref_image = cv2.imread(self.reference_image_path) | |
| if ref_image is not None: | |
| # macOS ๋ฉ๋ชจ๋ฆฌ ์ต์ ํ | |
| if ref_image.shape[0] > 1024 or ref_image.shape[1] > 1024: | |
| # ํฐ ์ด๋ฏธ์ง๋ ๋ฏธ๋ฆฌ ๋ฆฌ์ฌ์ด์ฆํ์ฌ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ ๊ฐ์ | |
| scale = min(1024 / ref_image.shape[0], 1024 / ref_image.shape[1]) | |
| if scale < 1: | |
| new_width = int(ref_image.shape[1] * scale) | |
| new_height = int(ref_image.shape[0] * scale) | |
| ref_image = cv2.resize(ref_image, (new_width, new_height)) | |
| self._ref_image_cache = cv2.cvtColor(ref_image, cv2.COLOR_BGR2RGB) | |
| # ResNet ์๋ฒ ๋ฉ ๊ณ์ฐ ๋ฐ ์บ์ | |
| if self.resnet_model is not None: | |
| try: | |
| pil_img = Image.fromarray(self._ref_image_cache) | |
| img_t = self.preprocess(pil_img).unsqueeze(0).to(self.device) | |
| with torch.no_grad(): | |
| self._ref_embedding = self.resnet_model(img_t).flatten() | |
| except Exception as e: | |
| print(f"์ฐธ์กฐ ์ด๋ฏธ์ง ์๋ฒ ๋ฉ ์คํจ: {e}") | |
| self._cache_loaded = True | |
| # ๋ฉ๋ชจ๋ฆฌ ์ ๋ฆฌ | |
| del ref_image | |
| gc.collect() | |
| return self._ref_image_cache | |
| def _get_memory_usage(self): | |
| """ํ์ฌ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ ๋ฐํํฉ๋๋ค.""" | |
| try: | |
| import psutil | |
| process = psutil.Process() | |
| memory_info = process.memory_info() | |
| return memory_info.rss / 1024 / 1024 # MB ๋จ์ | |
| except (ImportError, AttributeError): | |
| # macOS๋ ๋ค๋ฅธ ํ๊ฒฝ์์ psutil์ด ์๊ฑฐ๋ ๋์ํ์ง ์๋ ๊ฒฝ์ฐ | |
| try: | |
| import resource | |
| # getrusage๋ฅผ ํตํ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ ์ธก์ | |
| usage = resource.getrusage(resource.RUSAGE_SELF) | |
| return usage.ru_maxrss / 1024 # KB -> MB | |
| except: | |
| return 0 | |
| def calculate_similarity(self, image1, image2): | |
| try: | |
| # 1) ResNet Feature Similarity (Semantic Similarity) - ๊ฐ์ฅ ์ค์ | |
| resnet_score = 0.0 | |
| if self.resnet_model is not None and self._ref_embedding is not None: | |
| try: | |
| # ์ฌ์ฉ์ ์ด๋ฏธ์ง ์ ์ฒ๋ฆฌ | |
| pil_img = Image.fromarray(image2) # image2 is RGB numpy array | |
| img_t = self.preprocess(pil_img).unsqueeze(0).to(self.device) | |
| with torch.no_grad(): | |
| user_emb = self.resnet_model(img_t).flatten() | |
| # Cosine Similarity | |
| cos_sim = torch.nn.functional.cosine_similarity( | |
| self._ref_embedding.unsqueeze(0), | |
| user_emb.unsqueeze(0) | |
| ).item() | |
| # Sigmoid Scoring Formula | |
| # Sim 0.61 (Bad) -> Score 14 | |
| # Sim 0.77 (Good) -> Score 80 | |
| # Sim 0.92 (Perfect) -> Score 99 | |
| # Formula: 100 / (1 + exp(-20 * (sim - 0.7))) | |
| resnet_score = 100 / (1 + np.exp(-20 * (cos_sim - 0.7))) | |
| except Exception as e: | |
| print(f"ResNet ๊ณ์ฐ ์ค๋ฅ: {e}") | |
| resnet_score = 0.0 | |
| # 2) ๊ทธ๋ ์ด์ค์ผ์ผ ๋ณํ (๊ธฐ์กด ๋ก์ง ์ ์ง) | |
| if image1.ndim == 3: | |
| gray1 = cv2.cvtColor(image1, cv2.COLOR_RGB2GRAY) | |
| else: | |
| gray1 = image1.copy() | |
| if image2.ndim == 3: | |
| gray2 = cv2.cvtColor(image2, cv2.COLOR_RGB2GRAY) | |
| else: | |
| gray2 = image2.copy() | |
| # 3) ๊ฐ ์ด๋ฏธ์ง๋ฅผ ๋ ๋ฆฝ์ ์ผ๋ก ํ์ค ํฌ๊ธฐ๋ก ๋ฆฌ์ฌ์ด์ฆ (512x512) | |
| target_size = (512, 512) | |
| gray1 = cv2.resize(gray1, target_size, interpolation=cv2.INTER_LINEAR) | |
| gray2 = cv2.resize(gray2, target_size, interpolation=cv2.INTER_LINEAR) | |
| # 4) SSIM ๊ณ์ฐ (๊ตฌ์กฐ์ ์ ์ฌ๋) | |
| try: | |
| ssim_score = ssim(gray1.astype(np.float32), gray2.astype(np.float32)) | |
| except: | |
| # SSIM ๊ณ์ฐ ์คํจ์ MSE ๊ธฐ๋ฐ ๋์ฒด | |
| mse = np.mean((gray1.astype(np.float32) - gray2.astype(np.float32)) ** 2) | |
| ssim_score = 1 / (1 + mse / 10000) | |
| # 5) PSNR ๊ณ์ฐ (ํฝ์ ๋จ์ ์ ์ฌ๋) | |
| mse = np.mean((gray1.astype(np.float32) - gray2.astype(np.float32)) ** 2) | |
| if mse == 0: | |
| psnr_score = 1.0 | |
| else: | |
| psnr_score = 20 * np.log10(255.0 / np.sqrt(mse)) | |
| # PSNR์ 0-1 ๋ฒ์๋ก ๋ ๊ด๋ํ๊ฒ ์ ๊ทํ (๋ณดํต PSNR์ 20-40 ๋ฒ์) | |
| psnr_score = min(psnr_score / 40.0, 1.0) | |
| # 6) ํ์คํ ๊ทธ๋จ ์ ์ฌ๋ | |
| hist1 = cv2.calcHist([gray1], [0], None, [256], [0, 256]) | |
| hist2 = cv2.calcHist([gray2], [0], None, [256], [0, 256]) | |
| hist_corr = cv2.compareHist(hist1, hist2, cv2.HISTCMP_CORREL) | |
| hist_score = (hist_corr + 1) / 2 # -1~1 โ 0~1 | |
| # 7) ์ต์ข ์ ์ ๊ณ์ฐ (ResNet ๋น์ค ๋ํญ ๊ฐํ) | |
| # ResNet ๋ชจ๋ธ์ด ์์ผ๋ฉด ResNet 80%, SSIM 10%, Hist 10% | |
| if self.resnet_model is not None: | |
| final_score = (resnet_score * 0.8) + (ssim_score * 100 * 0.1) + (hist_score * 100 * 0.1) | |
| else: | |
| print(f"ResNet ๋ชจ๋ธ์ด ์์ด์ SSIM 70%, Hist 30%๋ก ๊ณ์ฐ") | |
| final_score = (ssim_score * 0.7 + hist_score * 0.3) * 100 | |
| # 8) PSNR์ด ๋์ผ๋ฉด ์ฝ๊ฐ์ ๋ณด๋์ค (์ต๋ 5์ ) | |
| if psnr_score > 0.8: | |
| bonus = min((psnr_score - 0.8) * 25, 5) | |
| final_score = min(final_score + bonus, 100) | |
| return { | |
| 'ssim': float(ssim_score), | |
| 'psnr': float(psnr_score * 100), | |
| 'histogram': float(hist_score), | |
| 'resnet': float(resnet_score), # ๊ฒฐ๊ณผ์ ํฌํจ | |
| 'final_score': float(final_score) | |
| } | |
| except Exception as e: | |
| print(f"์ ์ฌ๋ ๊ณ์ฐ ์ค๋ฅ: {e}") | |
| return {'ssim':0.0,'psnr':0.0,'histogram':0.0,'resnet':0.0,'final_score':0.0} | |
| def process_image(self, uploaded_image, username): | |
| """์ ๋ก๋๋ ์ด๋ฏธ์ง๋ฅผ ์ฒ๋ฆฌํ๊ณ ์ ์๋ฅผ ๊ณ์ฐํฉ๋๋ค.""" | |
| if uploaded_image is None: | |
| return "๐ค ์ด๋ฏธ์ง๋ฅผ ์ ๋ก๋ํด์ฃผ์ธ์.", self.get_leaderboard_df() | |
| # ์ฌ์ฉ์๋ช ๊ฒ์ฆ ์ ๊ฑฐ - ์ด๋ค ์ด๋ฆ์ด๋ ํ์ฉ | |
| if not username or not username.strip(): | |
| return "โ ์ฌ์ฉ์ ์ด๋ฆ์ ์ ๋ ฅํด์ฃผ์ธ์.", self.get_leaderboard_df() | |
| username = username.strip() | |
| # ๋์์ฑ ์ ์ด - ํ ๋ฒ์ ํ๋์ ์ด๋ฏธ์ง๋ง ์ฒ๋ฆฌ | |
| with self._processing_lock: | |
| try: | |
| # ์บ์๋ ์ฐธ์กฐ ์ด๋ฏธ์ง ์ฌ์ฉ | |
| ref_image = self._load_reference_image() | |
| if ref_image is None: | |
| return f"์ฐธ์กฐ ์ด๋ฏธ์ง({self.reference_image_path})๋ฅผ ๋ก๋ํ ์ ์์ต๋๋ค.", None | |
| # ์ ๋ก๋๋ ์ด๋ฏธ์ง๋ฅผ numpy ๋ฐฐ์ด๋ก ๋ณํ | |
| if isinstance(uploaded_image, str): | |
| # ํ์ผ ๊ฒฝ๋ก์ธ ๊ฒฝ์ฐ | |
| user_image = cv2.imread(uploaded_image) | |
| if user_image is None: | |
| return "์ ๋ก๋๋ ์ด๋ฏธ์ง๋ฅผ ์ฝ์ ์ ์์ต๋๋ค.", None | |
| user_image = cv2.cvtColor(user_image, cv2.COLOR_BGR2RGB) | |
| else: | |
| # PIL Image์ธ ๊ฒฝ์ฐ | |
| user_image = np.array(uploaded_image) | |
| if user_image is None or user_image.size == 0: | |
| return "์ ๋ก๋๋ ์ด๋ฏธ์ง๊ฐ ์ ํจํ์ง ์์ต๋๋ค.", None | |
| # ์ด๋ฏธ์ง ํฌ๊ธฐ ํ์ธ | |
| if user_image.shape[0] < 10 or user_image.shape[1] < 10: | |
| return "์ด๋ฏธ์ง๊ฐ ๋๋ฌด ์์ต๋๋ค. ์ต์ 10x10 ํฝ์ ์ด์์ด์ด์ผ ํฉ๋๋ค.", None | |
| # ์ ์ฌ๋ ๊ณ์ฐ | |
| similarity_scores = self.calculate_similarity(ref_image, user_image) | |
| # ๋ฉ๋ชจ๋ฆฌ ์ ๋ฆฌ (macOS ์ต์ ํ) | |
| del user_image | |
| if 'ref_image' in locals(): | |
| del ref_image | |
| gc.collect() | |
| # macOS์์ ๋ฉ๋ชจ๋ฆฌ ๊ฐ์ ์ ๋ฆฌ | |
| import platform | |
| if platform.system() == 'Darwin': # macOS | |
| import ctypes | |
| try: | |
| libc = ctypes.CDLL('libc.dylib') | |
| libc.malloc_trim(0) | |
| except: | |
| pass | |
| # ๋ฆฌ๋๋ณด๋์ ์ถ๊ฐ (JSON ์ง๋ ฌํ๋ฅผ ์ํด float๋ก ๋ณํ) | |
| entry = { | |
| 'username': username, | |
| 'score': float(round(similarity_scores['final_score'], 2)), | |
| 'date': datetime.now().strftime('%Y-%m-%d %H:%M:%S'), | |
| 'ssim': float(round(similarity_scores['ssim'], 4)), | |
| 'psnr': float(round(similarity_scores['psnr'], 2)), | |
| 'histogram': float(round(similarity_scores['histogram'], 4)), | |
| 'resnet': float(round(similarity_scores.get('resnet', 0.0), 2)) | |
| } | |
| # ๊ฐ์ ์ด๋ฆ์ ๊ธฐ์กด ๊ธฐ๋ก์ด ์๋์ง ํ์ธํ๊ณ , ๋ ๋์ ์ ์๋ง ์ ์ง | |
| existing_indices = [i for i, data in enumerate(self.leaderboard_data) if data['username'] == username] | |
| if existing_indices: | |
| # ๊ธฐ์กด ๊ธฐ๋ก ์ค ๊ฐ์ฅ ๋์ ์ ์ ์ฐพ๊ธฐ | |
| existing_scores = [self.leaderboard_data[i]['score'] for i in existing_indices] | |
| max_existing_score = max(existing_scores) | |
| # ์ ์ ์๊ฐ ๋ ๋์ผ๋ฉด ๊ธฐ์กด ๊ธฐ๋ก๋ค์ ๋ชจ๋ ์ ๊ฑฐํ๊ณ ์ ๊ธฐ๋ก ์ถ๊ฐ | |
| if entry['score'] > max_existing_score: | |
| # ๊ธฐ์กด ๊ธฐ๋ก๋ค์ ์ญ์์ผ๋ก ์ ๊ฑฐ (์ธ๋ฑ์ค ๋ณ๊ฒฝ ๋ฐฉ์ง) | |
| for i in sorted(existing_indices, reverse=True): | |
| del self.leaderboard_data[i] | |
| self.leaderboard_data.append(entry) | |
| self.save_leaderboard() | |
| # ๊ฐฑ์ ๋ ๊ฒฝ์ฐ์ ๋ฉ์์ง | |
| result_message = f"""๐ ๋๋จํด์! ์๋ก์ด ์ต๊ณ ๊ธฐ๋ก์ ๋๋ค! | |
| ๐ค {username}๋ | |
| ๐ ์ ์: {entry['score']:.0f}์ | |
| ๐ ์ด์ ์ต๊ณ : {max_existing_score:.0f}์ | |
| โ ๋ฆฌ๋๋ณด๋์ ๋ฑ๋ก๋์์ต๋๋ค! | |
| ๐ {entry['date']}""" | |
| else: | |
| # ์ ์ ์๊ฐ ๋ ๋ฎ๊ฑฐ๋ ๊ฐ์ผ๋ฉด ๋ฆฌ๋๋ณด๋๋ ์ ๋ฐ์ดํธํ์ง ์์ | |
| result_message = f"""๐ฏ ์ ์๊ฐ ๊ณ์ฐ๋์์ต๋๋ค! | |
| ๐ค {username}๋ | |
| ๐ ํ์ฌ ์ ์: {entry['score']:.0f}์ | |
| ๐ ์ต๊ณ ์ ์: {max_existing_score:.0f}์ | |
| ๐ช ์กฐ๊ธ๋ง ๋ ๋ ธ๋ ฅํ๋ฉด ์ต๊ณ ๊ธฐ๋ก์ ๊ฐฑ์ ํ ์ ์์ ๊ฒ ๊ฐ์์! | |
| ๋ค์ ์๋ํด๋ณด์ธ์!""" | |
| else: | |
| # ๊ธฐ์กด ๊ธฐ๋ก์ด ์์ผ๋ฉด ์๋ก ์ถ๊ฐ | |
| self.leaderboard_data.append(entry) | |
| self.save_leaderboard() | |
| # ์๋ก ๋ฑ๋ก๋ ๊ฒฝ์ฐ์ ๋ฉ์์ง | |
| result_message = f"""๐ ์ฒซ ๋ฑ๋ก์ ์ถํํฉ๋๋ค! | |
| ๐ค {username}๋ | |
| ๐ ์ ์: {entry['score']:.0f}์ | |
| โ ๋ฆฌ๋๋ณด๋์ ๋ฑ๋ก๋์์ต๋๋ค! | |
| ๐ {entry['date']}""" | |
| return result_message, self.get_leaderboard_df() | |
| except Exception as e: | |
| import traceback | |
| error_msg = f"์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค: {str(e)}\n\n์์ธ ์ ๋ณด:\n{traceback.format_exc()}" | |
| return error_msg, None | |
| def get_leaderboard_df(self): | |
| """๋ฆฌ๋๋ณด๋๋ฅผ DataFrame์ผ๋ก ๋ฐํํฉ๋๋ค.""" | |
| if not self.leaderboard_data: | |
| return pd.DataFrame(columns=['์์', '์ฌ์ฉ์๋ช ', '์ ์', '๋ ์ง']) | |
| # ์ ์ ๊ธฐ์ค์ผ๋ก ์ ๋ ฌ | |
| sorted_data = sorted(self.leaderboard_data, key=lambda x: x['score'], reverse=True) | |
| # DataFrame ์์ฑ | |
| df_data = [] | |
| for i, entry in enumerate(sorted_data, 1): | |
| df_data.append({ | |
| '์์': i, | |
| '์ฌ์ฉ์๋ช ': entry['username'], | |
| '์ ์': entry['score'], | |
| '๋ ์ง': entry['date'] | |
| }) | |
| return pd.DataFrame(df_data) | |
| def authenticate_admin(self, password): | |
| """๊ด๋ฆฌ์ ์ธ์ฆ""" | |
| if password == self.admin_password: | |
| self.admin_authenticated = True | |
| return "โ ๊ด๋ฆฌ์ ์ธ์ฆ์ด ์๋ฃ๋์์ต๋๋ค.", True | |
| else: | |
| self.admin_authenticated = False | |
| return "โ ์๋ชป๋ ๋น๋ฐ๋ฒํธ์ ๋๋ค.", False | |
| def update_reference_image(self, new_image): | |
| """์ฐธ์กฐ ์ด๋ฏธ์ง ์ ๋ฐ์ดํธ""" | |
| if not self.admin_authenticated: | |
| return "โ ๊ด๋ฆฌ์ ์ธ์ฆ์ด ํ์ํฉ๋๋ค." | |
| try: | |
| if new_image is None: | |
| return "โ ์ด๋ฏธ์ง๋ฅผ ์ ๋ก๋ํด์ฃผ์ธ์." | |
| # ์ด๋ฏธ์ง๋ฅผ ์ ์ฅ | |
| new_image.save(self.reference_image_path) | |
| return f"โ ์ฐธ์กฐ ์ด๋ฏธ์ง๊ฐ ์ ๋ฐ์ดํธ๋์์ต๋๋ค. ({self.reference_image_path})" | |
| except Exception as e: | |
| return f"โ ์ด๋ฏธ์ง ์ ์ฅ ์ค ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค: {str(e)}" | |
| def clear_leaderboard(self): | |
| """๋ฆฌ๋๋ณด๋๋ฅผ ์ด๊ธฐํํฉ๋๋ค.""" | |
| if not self.admin_authenticated: | |
| return "โ ๊ด๋ฆฌ์ ์ธ์ฆ์ด ํ์ํฉ๋๋ค.", self.get_leaderboard_df() | |
| self.leaderboard_data = [] | |
| self.save_leaderboard() | |
| return "โ ๋ฆฌ๋๋ณด๋๊ฐ ์ด๊ธฐํ๋์์ต๋๋ค.", pd.DataFrame(columns=['์์', '์ฌ์ฉ์๋ช ', '์ ์', '๋ ์ง']) | |
| # โโ ์ ์ญ ๋ฆฌ๋๋ณด๋ ์ธ์คํด์ค (CLASSES ๊ธฐ๋ฐ ๋์ ์์ฑ + ์ฐ์ต) โโ | |
| leaderboards = {} | |
| for _cls in CLASSES: | |
| leaderboards[_class_key(_cls)] = ImageSimilarityLeaderboard("label2.jpg", f"{_class_key(_cls)}.json") | |
| leaderboards['practice'] = ImageSimilarityLeaderboard("label2.jpg", "practice.json") | |
| # โโ ๋ฒ์ฉ ์ฒ๋ฆฌ ํจ์ โโ | |
| def process_user_image(class_key, image, username): | |
| """์ด๋ฏธ์ง ์ฒ๋ฆฌ (๋ชจ๋ ๋ฐ ๊ณต์ฉ)""" | |
| return leaderboards[class_key].process_image(image, username) | |
| def get_current_leaderboard(class_key): | |
| """ํ์ฌ ๋ฆฌ๋๋ณด๋ ๋ฐํ (๋ชจ๋ ๋ฐ ๊ณต์ฉ)""" | |
| return leaderboards[class_key].get_leaderboard_df() | |
| def check_and_update_leaderboard(class_key): | |
| """๋ฆฌ๋๋ณด๋ ์ ๋ฐ์ดํธ ํ์ธ ๋ฐ ๋ฐํ (๋ชจ๋ ๋ฐ ๊ณต์ฉ)""" | |
| leaderboards[class_key].check_for_updates() | |
| return leaderboards[class_key].get_leaderboard_df() | |
| def create_interface(): | |
| """Gradio ์ธํฐํ์ด์ค ์์ฑ (CLASSES ๊ธฐ๋ฐ ๋์ ํญ)""" | |
| with gr.Blocks(title="๋น์ทํ ์ด๋ฏธ์ง๋ฅผ ๋ง๋ค์ด์ฃผ์ธ์!", theme=gr.themes.Soft()) as demo: | |
| gr.Markdown(""" | |
| # ๐ ๋กฏ๋ฐ ๋น์ ์คํ๋์ค ๋ฆฌ๋๋ณด๋ | |
| """) | |
| # ๋ชจ๋ ๋ฆฌ๋๋ณด๋ ์ถ๋ ฅ ์์ ฏ์ ๋ชจ์๋ ๋์ ๋๋ฆฌ | |
| leaderboard_outputs = {} | |
| # ํญ ์์ฑ | |
| with gr.Tabs(): | |
| # โโ ์ฐ์ต ํญ (ํญ์ ์ฒซ ๋ฒ์งธ) โโ | |
| with gr.Tab("๐ ์ฐ์ต"): | |
| gr.Markdown("### ๐ก ์ฐ์ต์ฉ ํญ (๋ฉ์ธ)") | |
| gr.Markdown("์ ๋ก๋ ๋ฐ ์ด๋ฏธ์ง ์ ์ฌ๋๋ฅผ ํ ์คํธํด๋ณผ ์ ์๋ ์ฐ์ต ๊ณต๊ฐ์ ๋๋ค.") | |
| gr.Markdown("---") | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| gr.Markdown("### ๐ค ์ด๋ฏธ์ง ์ ๋ก๋ (์ฐ์ต)") | |
| image_input_practice = gr.Image( | |
| label="๋น๊ตํ ์ด๋ฏธ์ง๋ฅผ ์ ๋ก๋ํ์ธ์", | |
| type="pil", | |
| height=300 | |
| ) | |
| username_input_practice = gr.Textbox( | |
| label="์ฌ์ฉ์ ์ด๋ฆ (์ฐ์ต์ฉ)", | |
| placeholder="์ด๋ฆ์ ์ ๋ ฅํ์ธ์", | |
| max_lines=1 | |
| ) | |
| submit_btn_practice = gr.Button("๐ ์ ์ฌ๋ ํ ์คํธ", variant="primary", size="lg") | |
| with gr.Column(scale=1): | |
| gr.Markdown("### ๐ ํ ์คํธ ๊ฒฐ๊ณผ") | |
| result_output_practice = gr.Textbox( | |
| label="์ ์ฌ๋ ๋ถ์ ๊ฒฐ๊ณผ", | |
| lines=12, | |
| interactive=False | |
| ) | |
| gr.Markdown("### ๐ ์ฐ์ต ๋ฆฌ๋๋ณด๋") | |
| leaderboard_output_practice = gr.Dataframe( | |
| headers=["์์", "์ฌ์ฉ์๋ช ", "์ ์", "๋ ์ง"], | |
| datatype=["number", "str", "number", "str"], | |
| interactive=False | |
| ) | |
| leaderboard_outputs['practice'] = leaderboard_output_practice | |
| # ์ฐ์ต ํญ ์ด๋ฒคํธ ํธ๋ค๋ฌ | |
| submit_btn_practice.click( | |
| fn=lambda img, name: process_user_image('practice', img, name), | |
| inputs=[image_input_practice, username_input_practice], | |
| outputs=[result_output_practice, leaderboard_output_practice] | |
| ) | |
| # โโ ๋ฐ๋ณ ํญ (CLASSES ๊ธฐ๋ฐ ๋์ ์์ฑ) โโ | |
| for idx, class_name in enumerate(CLASSES): | |
| icon = _TAB_ICONS[idx % len(_TAB_ICONS)] | |
| key = _class_key(class_name) | |
| with gr.Tab(f"{icon} {class_name}"): | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| gr.Markdown(f"### ๐ค ์ด๋ฏธ์ง ์ ๋ก๋ ({class_name})") | |
| image_input = gr.Image( | |
| label="๋น๊ตํ ์ด๋ฏธ์ง๋ฅผ ์ ๋ก๋ํ์ธ์", | |
| type="pil", | |
| height=300 | |
| ) | |
| username_input = gr.Textbox( | |
| label="์ฌ์ฉ์ ์ด๋ฆ", | |
| placeholder="์ด๋ฆ์ ์ ๋ ฅํ์ธ์", | |
| max_lines=1 | |
| ) | |
| submit_btn = gr.Button("๐ ์ ์ ๊ณ์ฐ ๋ฐ ๋ฑ๋ก", variant="primary", size="lg") | |
| with gr.Column(scale=1): | |
| gr.Markdown(f"### ๐ ๊ฒฐ๊ณผ ({class_name})") | |
| result_output = gr.Textbox( | |
| label="๊ณ์ฐ ๊ฒฐ๊ณผ", | |
| lines=10, | |
| interactive=False | |
| ) | |
| gr.Markdown(f"### ๐ {class_name} ๋ฆฌ๋๋ณด๋") | |
| leaderboard_output = gr.Dataframe( | |
| headers=["์์", "์ฌ์ฉ์๋ช ", "์ ์", "๋ ์ง"], | |
| datatype=["number", "str", "number", "str"], | |
| interactive=False | |
| ) | |
| leaderboard_outputs[key] = leaderboard_output | |
| # ํด๋ก์ ์์ key ๊ฐ์ ์บก์ฒํ๊ธฐ ์ํด default argument ์ฌ์ฉ | |
| submit_btn.click( | |
| fn=lambda img, name, k=key: process_user_image(k, img, name), | |
| inputs=[image_input, username_input], | |
| outputs=[result_output, leaderboard_output] | |
| ) | |
| # โโ ๋ชจ๋ ํค ์์ (practice ๋จผ์ , ์ดํ CLASSES ์์) โโ | |
| all_keys = ['practice'] + [_class_key(c) for c in CLASSES] | |
| all_outputs = [leaderboard_outputs[k] for k in all_keys] | |
| # ํ์ด์ง ๋ก๋ ์ ๋ชจ๋ ๋ฆฌ๋๋ณด๋ ํ์ | |
| demo.load( | |
| fn=lambda: tuple(get_current_leaderboard(k) for k in all_keys), | |
| outputs=all_outputs | |
| ) | |
| # ์ค์๊ฐ ์ ๋ฐ์ดํธ (10์ด๋ง๋ค - ๋ชจ๋ ํญ ์ ๋ฐ์ดํธ) | |
| timer = gr.Timer(value=10) | |
| timer.tick( | |
| fn=lambda: tuple(check_and_update_leaderboard(k) for k in all_keys), | |
| outputs=all_outputs | |
| ) | |
| return demo | |
| def main(): | |
| """๋ฉ์ธ ํจ์""" | |
| print("๐ ์ด๋ฏธ์ง ์ ์ฌ๋ ๋ฆฌ๋๋ณด๋ ์์คํ ์ ์์ํฉ๋๋ค...") | |
| print("๐ ์ฐธ์กฐ ์ด๋ฏธ์ง: label2.jpg") | |
| print("๐พ ๋ฐ์ดํฐ ํ์ผ:") | |
| for cls in CLASSES: | |
| key = _class_key(cls) | |
| print(f" โข {cls}: {key}.json") | |
| print(f" โข ์ฐ์ต: practice.json") | |
| # ๊ฐ ๋ฐ๋ณ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ ์ฒดํฌ | |
| for class_name, lb in leaderboards.items(): | |
| initial_memory = lb._get_memory_usage() | |
| print(f"๐พ {class_name} ์ด๊ธฐ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋: {initial_memory:.1f}MB") | |
| if not os.path.exists("label2.jpg"): | |
| print("โ ๏ธ ๊ฒฝ๊ณ : ์ฐธ์กฐ ์ด๋ฏธ์ง(label2.jpg)๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค!") | |
| print(" label2.jpg ํ์ผ์ ํ๋ก์ ํธ ๋ฃจํธ์ ๋ฐฐ์นํด์ฃผ์ธ์.") | |
| # Gradio ์ธํฐํ์ด์ค ์์ฑ ๋ฐ ์คํ | |
| demo = create_interface() | |
| print("๐ ์๋ฒ๋ฅผ ์์ํฉ๋๋ค...") | |
| print("๐ ์ต์ ํ ์ฌํญ:") | |
| print(" โข ์ฐธ์กฐ ์ด๋ฏธ์ง ์บ์ฑ ํ์ฑํ") | |
| print(" โข ์ด๋ฏธ์ง ํฌ๊ธฐ ์ ํ: 512x512") | |
| print(" โข ๋์์ฑ ์ ์ด ํ์ฑํ") | |
| print(" โข ๋ฉ๋ชจ๋ฆฌ ์ ๋ฆฌ ์๋ํ") | |
| print(" โข ์ค์๊ฐ ์ ๋ฐ์ดํธ: 10์ด ๊ฐ๊ฒฉ") | |
| print(f" โข {len(CLASSES)+1}๊ฐ ํญ๋ณ ๋ ๋ฆฝ ๋ฆฌ๋๋ณด๋ ์ด์ ({len(CLASSES)}๊ฐ ๋ฐ + ์ฐ์ต)") | |
| # ์ธ๋ถ ๊ณต์ ์ฐ์ ์๋ | |
| print("\n๐ ์ธ๋ถ ์ ๊ทผ ์๋ ์ค...") | |
| try: | |
| demo.launch( | |
| # server_name="0.0.0.0", | |
| # server_port=9900, | |
| # share=False, # ๋ก์ปฌ์์ share=True๋ ๋ถํ์ํ ๊ฒฝ๊ณ ๋ฅผ ์ ๋ฐํ๋ฏ๋ก False๋ก ๋ณ๊ฒฝ | |
| # show_error=False, | |
| # quiet=False, | |
| # ssr_mode=False # SSR ๋ชจ๋ ๋นํ์ฑํ๋ก ์คํ์ ๊ธฐ๋ฅ ๊ฒฝ๊ณ ์ ๊ฑฐ | |
| ) | |
| except Exception as e: | |
| print(f"โ ์ธ๋ถ ๊ณต์ ์คํจ: {e}") | |
| print("๐ ๋ก์ปฌ ๋คํธ์ํฌ ๋ชจ๋๋ก ์ ํ...") | |
| demo.launch( | |
| server_name="0.0.0.0", | |
| server_port=9900, | |
| share=False, # ๋ก์ปฌ ํ๊ฒฝ์์๋ share=False๋ก ์ ์ง | |
| show_error=True, | |
| quiet=False, | |
| ssr_mode=False # SSR ๋ชจ๋ ๋นํ์ฑํ | |
| ) | |
| if __name__ == "__main__": | |
| main() | |