import gradio as gr from PIL import Image, ImageOps import numpy as np import easyocr from pokedex import ( get_base_hp, estimate_level_from_hp, get_english_name, get_pokemon_info, ) reader = easyocr.Reader(['en'], gpu=False) def find_pokemon_from_name_and_hp(name: str, hp: int) -> str: name_en = get_english_name(name) if "❌" in name_en: return "❌ Pokémon not recognized." try: base = get_base_hp(name_en) level = estimate_level_from_hp(int(hp), base) if not level: return "⚠️ Could not estimate level with provided HP." info = get_pokemon_info(name_en, level) return f"## 📊 Estimated Level: {level}\n\n{info}" except Exception as e: return f"⚠️ Error: {str(e)}" def find_pokemon_from_name_and_level(name: str, level: int) -> str: name_en = get_english_name(name) if "❌" in name_en: return "❌ Pokémon not recognized." try: info = get_pokemon_info(name_en, level) return f"## 📊 Level: {level}\n\n{info}" except Exception as e: return f"⚠️ Error: {str(e)}" manual_hp_interface = gr.Interface( fn=find_pokemon_from_name_and_hp, inputs=[ gr.Text(label="Pokémon Name (EN or FR)"), gr.Number(label="Observed HP") ], outputs="markdown", title="Estimate Level from HP", description="Enter a Pokémon name and its observed HP to estimate its level and view full info." ) manual_level_interface = gr.Interface( fn=find_pokemon_from_name_and_level, inputs=[ gr.Text(label="Pokémon Name (EN or FR)"), gr.Slider(minimum=1, maximum=100, value=50, step=1, label="Level") ], outputs="markdown", title="Pokémon Stats at Specific Level", description="Enter a Pokémon name and a level to get its full info sheet." ) # 📌 Mode OCR def find_pokemon_from_card_image(image: Image.Image, source: str) -> str: if image is None: return "❌ No image provided." if source == "webcam": image = ImageOps.mirror(image) image_np = np.array(image) results = reader.readtext(image_np) all_texts = "### 📄 OCR Detected Texts:\n" for i, (bbox, text, conf) in enumerate(results): all_texts += f"- Text #{i+1}: `{text.strip()}` (confidence: {round(conf, 2)})\n" card_name = None if len(results) >= 1: text1 = results[0][1].strip().upper() if "IVEA" not in text1: card_name = get_english_name(results[0][1].strip()) elif len(results) >= 2: card_name = get_english_name(results[1][1].strip()) hp = None for (bbox, text, conf) in results[:5]: text_clean = text.strip() if conf > 0.9 and text_clean.isdigit(): hp = int(text_clean) break level_info = "" pokemon_sheet = "" if hp is not None and card_name and "❌" not in card_name: try: base_hp = get_base_hp(card_name) level = estimate_level_from_hp(hp, base_hp) if level: level_info = f"## 📊 Estimated Level: {level}" pokemon_sheet = get_pokemon_info(card_name, level) else: level_info = "⚠️ Unable to estimate level from provided data." except Exception as e: level_info = f"⚠️ Error while processing: {str(e)}" else: level_info = "⚠️ Not enough information to estimate level." return f""" ### 🃏 OCR Result **Pokémon Name (EN)**: {card_name or '❓ Not detected'} **HP**: {hp if hp is not None else '❓ Not detected'} {level_info} --- {pokemon_sheet} """.strip() ocr_interface = gr.Interface( fn=find_pokemon_from_card_image, inputs=[ gr.Image(type="pil", label="Pokémon Card Image", height=300, width=300), gr.Radio(["upload", "webcam"], label="Image Source", value="upload") ], outputs="markdown", title="OCR Pokémon Scanner", description="Upload or scan a Pokémon card to automatically extract info and estimate level.", ) # 🌐 Multi-MCP Tabbed Interface demo = gr.TabbedInterface( interface_list=[manual_hp_interface, manual_level_interface, ocr_interface], tab_names=["Manual from HP", "Manual from level", "Image OCR"] ) if __name__ == "__main__": demo.launch(mcp_server=True)