Benito
Add GoT House Predictor Gradio app
918ac7b
"""
Game of Thrones House Predictor - HuggingFace Gradio App
Space Name: got-house-predictor
This app provides a web interface for predicting Game of Thrones house affiliation
based on character traits and attributes.
"""
import gradio as gr
import pandas as pd
import numpy as np
import joblib
import json
import os
# Load model and metadata
def load_artifacts():
"""Load the trained model and metadata files."""
# Try different paths for model artifacts
possible_paths = [
".", # Current directory (HuggingFace Space root)
"./model_artifacts", # Subfolder
"./huggingface", # When running from project root
]
model = None
feature_columns = None
label_classes = None
for base_path in possible_paths:
model_path = os.path.join(base_path, "model.joblib")
features_path = os.path.join(base_path, "feature_columns.json")
labels_path = os.path.join(base_path, "label_classes.json")
if os.path.exists(model_path):
model = joblib.load(model_path)
with open(features_path, "r") as f:
feature_columns = json.load(f)
with open(labels_path, "r") as f:
label_classes = json.load(f)
print(f"Loaded artifacts from: {base_path}")
break
if model is None:
raise FileNotFoundError("Could not find model artifacts. Please ensure model.joblib, feature_columns.json, and label_classes.json are present.")
return model, feature_columns, label_classes
# Load artifacts at startup
try:
MODEL, FEATURE_COLUMNS, LABEL_CLASSES = load_artifacts()
print(f"Model loaded successfully!")
print(f"Number of features: {len(FEATURE_COLUMNS)}")
print(f"Label classes: {LABEL_CLASSES}")
except Exception as e:
print(f"Error loading model: {e}")
MODEL, FEATURE_COLUMNS, LABEL_CLASSES = None, None, None
# Define options for categorical inputs
REGIONS = ["The North", "The Riverlands", "The Vale", "The Westerlands",
"The Reach", "The Stormlands", "Dorne", "Iron Islands",
"The Crownlands", "Beyond the Wall", "Essos", "Unknown"]
ROLES = ["Ruler", "Knight", "Advisor", "Warrior", "Assassin",
"Maester", "Lord/Lady", "Commoner", "Merchant", "Other"]
ALIGNMENTS = ["Lawful Good", "Neutral Good", "Chaotic Good",
"Lawful Neutral", "True Neutral", "Chaotic Neutral",
"Lawful Evil", "Neutral Evil", "Chaotic Evil"]
STATUSES = ["Alive", "Dead", "Unknown"]
SPECIES = ["Human", "Other"]
def prepare_input(region, primary_role, alignment, status, species,
honour, ruthlessness, intelligence, combat_skill,
diplomacy, leadership,
strategic, impulsive, charismatic, vengeful, loyal, scheming):
"""Prepare input features to match training format."""
# Create base features dictionary
features = {
# Numerical features (1-5 scale)
"honour_1to5": honour,
"ruthlessness_1to5": ruthlessness,
"intelligence_1to5": intelligence,
"combat_skill_1to5": combat_skill,
"diplomacy_1to5": diplomacy,
"leadership_1to5": leadership,
# Boolean traits (convert to int)
"trait_strategic": int(strategic),
"trait_impulsive": int(impulsive),
"trait_charismatic": int(charismatic),
"trait_vengeful": int(vengeful),
"trait_loyal": int(loyal),
"trait_scheming": int(scheming),
# Feature set version (default)
"feature_set_version": 1.0
}
# Create one-hot encoded features for categorical columns
# Based on the training preprocessing
categorical_mappings = {
"region": region,
"primary_role": primary_role,
"alignment": alignment,
"status": status,
"species": species
}
# Initialize all one-hot features to 0
for col in FEATURE_COLUMNS:
if col not in features:
features[col] = 0
# Set the appropriate one-hot encoded columns to 1
for cat_name, cat_value in categorical_mappings.items():
col_name = f"{cat_name}_{cat_value}"
if col_name in features:
features[col_name] = 1
# Create DataFrame with correct column order
input_df = pd.DataFrame([features])
# Ensure all columns exist and are in correct order
for col in FEATURE_COLUMNS:
if col not in input_df.columns:
input_df[col] = 0
input_df = input_df[FEATURE_COLUMNS]
return input_df
def predict_house(region, primary_role, alignment, status, species,
honour, ruthlessness, intelligence, combat_skill,
diplomacy, leadership,
strategic, impulsive, charismatic, vengeful, loyal, scheming):
"""Predict the Game of Thrones house for given character traits."""
if MODEL is None:
return {"error": "Model not loaded"}
try:
# Prepare input
input_df = prepare_input(
region, primary_role, alignment, status, species,
honour, ruthlessness, intelligence, combat_skill,
diplomacy, leadership,
strategic, impulsive, charismatic, vengeful, loyal, scheming
)
# Get prediction
prediction = MODEL.predict(input_df)[0]
# Get prediction probabilities if available
if hasattr(MODEL, 'predict_proba'):
probabilities = MODEL.predict_proba(input_df)[0]
prob_dict = {
LABEL_CLASSES[i]: float(probabilities[i])
for i in range(len(LABEL_CLASSES))
}
return {
"predicted_house": prediction,
"probabilities": prob_dict
}
return {"predicted_house": prediction}
except Exception as e:
return {"error": str(e)}
def create_interface():
"""Create the Gradio interface."""
with gr.Blocks(title="Game of Thrones House Predictor", theme=gr.themes.Soft()) as demo:
gr.Markdown("""
# ๐Ÿฐ Game of Thrones House Predictor
Predict which Great House a character would belong to based on their traits and attributes!
This model was trained using Azure ML and predicts house affiliation using a Decision Tree classifier.
""")
with gr.Row():
with gr.Column():
gr.Markdown("### ๐Ÿ“ Background")
region = gr.Dropdown(choices=REGIONS, label="Region", value="The North")
primary_role = gr.Dropdown(choices=ROLES, label="Primary Role", value="Knight")
alignment = gr.Dropdown(choices=ALIGNMENTS, label="Alignment", value="True Neutral")
status = gr.Dropdown(choices=STATUSES, label="Status", value="Alive")
species = gr.Dropdown(choices=SPECIES, label="Species", value="Human")
with gr.Column():
gr.Markdown("### ๐Ÿ“Š Attributes (1-5)")
honour = gr.Slider(1, 5, value=3, step=1, label="Honour")
ruthlessness = gr.Slider(1, 5, value=3, step=1, label="Ruthlessness")
intelligence = gr.Slider(1, 5, value=3, step=1, label="Intelligence")
combat_skill = gr.Slider(1, 5, value=3, step=1, label="Combat Skill")
diplomacy = gr.Slider(1, 5, value=3, step=1, label="Diplomacy")
leadership = gr.Slider(1, 5, value=3, step=1, label="Leadership")
with gr.Row():
with gr.Column():
gr.Markdown("### ๐ŸŽญ Personality Traits")
with gr.Row():
strategic = gr.Checkbox(label="Strategic")
impulsive = gr.Checkbox(label="Impulsive")
charismatic = gr.Checkbox(label="Charismatic")
with gr.Row():
vengeful = gr.Checkbox(label="Vengeful")
loyal = gr.Checkbox(label="Loyal", value=True)
scheming = gr.Checkbox(label="Scheming")
predict_btn = gr.Button("๐Ÿ”ฎ Predict House", variant="primary", size="lg")
with gr.Row():
output = gr.JSON(label="Prediction Result")
predict_btn.click(
fn=predict_house,
inputs=[
region, primary_role, alignment, status, species,
honour, ruthlessness, intelligence, combat_skill,
diplomacy, leadership,
strategic, impulsive, charismatic, vengeful, loyal, scheming
],
outputs=output
)
gr.Markdown("""
---
### ๐Ÿ  About the Houses
The model predicts affiliation with the Great Houses of Westeros:
- **House Stark** - The North, honor and loyalty
- **House Lannister** - The Westerlands, wealth and power
- **House Targaryen** - Fire and Blood, dragons
- **House Baratheon** - The Stormlands, strength
- **House Greyjoy** - Iron Islands, naval prowess
- **House Tyrell** - The Reach, cunning and ambition
- **House Martell** - Dorne, passion and vengeance
- And more...
---
*Built with Azure ML + HuggingFace for MLOps Exam 2025*
""")
return demo
# Create and launch the app
if __name__ == "__main__":
demo = create_interface()
demo.launch()