Grandediw's picture
Update app.py
a3768e0 verified
raw
history blame
6.55 kB
import gradio as gr
import pandas as pd
import numpy as np
from xgboost import Booster, DMatrix
import requests
# Generate card_numbers
card_numbers = {
"Archers": 1, "Archer Queen": 2, "Baby Dragon": 3, "Balloon": 4, "Bandit": 5, "Barbarians": 6,
"Bats": 7, "Battle Healer": 8, "Battle Ram": 9, "Bomber": 10, "Bowler": 11, "Bush Goblins": 12,
"Cannon Cart": 13, "Cursed Hog": 14, "Dark Prince": 15, "Dart Goblin": 16, "Electro Dragon": 17,
"Electro Giant": 18, "Electro Spirit": 19, "Electro Wizard": 20, "Elite Barbarians": 21,
"Elixir Blob": 22, "Elixir Golem": 23, "Elixir Golemite": 24, "Executioner": 25, "Firecracker": 26,
"Fire Spirit": 27, "Fisherman": 28, "Flying Machine": 29, "Giant": 30, "Giant Skeleton": 31,
"Goblin Brawler": 32, "Goblin Gang": 33, "Goblin Demolisher": 34, "Goblin Giant": 35,
"Goblin Machine": 36, "Goblins": 37, "Goblinstein": 38, "Golden Knight": 39, "Golem": 40,
"Golemite": 41, "Guardienne": 42, "Guards": 43, "Hog Rider": 44, "Hunter": 45, "Heal Spirit": 46,
"Ice Golem": 47, "Ice Spirit": 48, "Ice Wizard": 49, "Inferno Dragon": 50, "Knight": 51,
"Lava Hound": 52, "Lava Pup": 53, "Little Prince": 54, "Lumberjack": 55, "Magic Archer": 56,
"Mega Knight": 57, "Mega Minion": 58, "Mighty Miner": 59, "Miner": 60, "Mini P.E.K.K.A.": 61,
"Minion Horde": 62, "Minions": 63, "Monk": 64, "Mother Witch": 65, "Monster": 66, "Musketeer": 67,
"Night Witch": 68, "P.E.K.K.A.": 69, "Phoenix": 70, "Reborn Phoenix": 71, "Prince": 72,
"Princess": 73, "Ram Rider": 74, "Rascal Boy": 75, "Rascal Girl": 76, "Royal Ghost": 77,
"Royal Giant": 78, "Royal Hogs": 79, "Royal Recruits": 80, "Skeleton Army": 81,
"Skeleton Barrel": 82, "Skeleton Dragons": 83, "Skeleton King": 84, "Skeletons": 85, "Sparky": 86,
"Spear Goblins": 87, "Suspicious Bush": 88, "Three Musketeers": 89, "Valkyrie": 90,
"Wall Breakers": 91, "Witch": 92, "Wizard": 93, "Zappies": 94, "Bomb Tower": 95, "Cannon": 96,
"Inferno Tower": 98, "Mortar": 99, "Tesla": 100, "X-Bow": 101, "Barbarian Hut": 102,
"Elixir Collector": 103, "Furnace": 104, "Goblin Cage": 105, "Goblin Drill": 106,
"Goblin Hut": 107, "Phoenix Egg": 108, "Tombstone": 109, "Arrows": 110, "Barbarian Barrel": 111,
"Earthquake": 112, "Fireball": 113, "Freeze": 114, "Giant Snowball": 115, "Lightning": 117,
"Poison": 118, "Rage": 119, "Rocket": 120, "Royal Delivery": 121, "The Log": 122, "Tornado": 123,
"Zap": 125, "Goblin Barrel": 132, "Graveyard": 139
}
# Generate card_images with normalized filenames
base_url = "https://raw.githubusercontent.com/RoyaleAPI/cr-api-assets/master/cards/"
card_images = {
card_name: f"{base_url}{card_name.lower().replace(' ', '-').replace('/', '-').replace('.', '')}.png"
for card_name in card_numbers.keys()
}
# Validate URLs
valid_card_images = {}
for card, url in card_images.items():
response = requests.head(url)
if response.status_code == 200:
valid_card_images[card] = url
# Define model-related functions
MODEL_PATH = "model.json"
def load_model(model_path):
"""Load the saved XGBoost model."""
model = Booster()
model.load_model(model_path)
return model
def deck_to_ids(deck, mapping):
"""Convert card names to IDs based on the mapping."""
return [mapping.get(card, 0) - 1 for card in deck]
def preprocess_deck(deck):
"""Prepare the selected deck for the model."""
deck_ids = deck_to_ids(deck, card_numbers)
num_choices = len(card_numbers)
one_hot = np.zeros(num_choices, dtype=int)
one_hot[np.array(deck_ids)] = 1
features = np.concatenate(([0, 0], one_hot))
return pd.DataFrame([features])
def predict_outcome(opponent_deck):
"""Make a prediction based on the opponent's deck."""
deck_data = preprocess_deck(opponent_deck)
dmatrix = DMatrix(deck_data)
prediction = model.predict(dmatrix)
return f"Probability of Winning: {prediction[0] * 100:.2f}%"
# Load the model
model = load_model(MODEL_PATH)
# Create Gradio Interface
with gr.Blocks(css="""
.card-container img {
width: 80px !important;
height: 80px !important;
object-fit: contain;
margin: 5px auto;
}
.card-container {
text-align: center;
padding: 5px;
border: 1px solid #ddd;
border-radius: 8px;
margin: 5px;
}
.checkbox-container {
margin-top: 5px;
}
""") as interface:
gr.Markdown("## Clash Royale Prediction")
gr.Markdown("Select 8 cards from the opponent's deck to predict the probability of winning!")
# State for tracking selected cards
selected_cards_display = gr.Markdown("Selected cards: 0/8")
def update_selection(*checkbox_values):
selected_count = sum(checkbox_values)
return f"Selected cards: {selected_count}/8"
# Create card grid using rows and columns
cards_per_row = 8
cards_list = list(valid_card_images.items())
all_checkboxes = []
for i in range(0, len(cards_list), cards_per_row):
with gr.Row():
for card, url in cards_list[i:i + cards_per_row]:
with gr.Column(elem_classes="card-container"):
gr.Image(value=url, show_label=False)
checkbox = gr.Checkbox(label=card, elem_classes="checkbox-container")
all_checkboxes.append(checkbox)
with gr.Row():
result = gr.Textbox(label="Prediction Result:", interactive=False)
clear_btn = gr.Button("Clear Selection")
predict_btn = gr.Button("Make Prediction", variant="primary")
def clear_selection():
return [False] * len(all_checkboxes) + ["Selected cards: 0/8", ""]
clear_btn.click(
clear_selection,
outputs=all_checkboxes + [selected_cards_display, result]
)
def validate_and_predict(*checkbox_values):
selected_cards = [
card for card, checked in zip(valid_card_images.keys(), checkbox_values)
if checked
]
if len(selected_cards) != 8:
return f"Error: Please select exactly 8 cards. You selected {len(selected_cards)}."
return predict_outcome(selected_cards)
predict_btn.click(
validate_and_predict,
inputs=all_checkboxes,
outputs=result
)
# Update the card count display
for checkbox in all_checkboxes:
checkbox.change(
update_selection,
inputs=all_checkboxes,
outputs=selected_cards_display
)
interface.launch()