Spaces:
Sleeping
Sleeping
| """ | |
| 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() | |