Melisa13 commited on
Commit
5b23fa7
·
verified ·
1 Parent(s): dc02066

Upload 4 files

Browse files
Files changed (4) hide show
  1. app.py +261 -0
  2. feature_names.json +59 -0
  3. model.pkl +3 -0
  4. requirements.txt +4 -0
app.py ADDED
@@ -0,0 +1,261 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Gradio application for Game of Thrones House Prediction
3
+ Interactive web interface for character house prediction
4
+ Deployed on HuggingFace Spaces
5
+ """
6
+
7
+ import gradio as gr
8
+ import pandas as pd
9
+ import joblib
10
+ import json
11
+ import os
12
+
13
+ # Model paths (HuggingFace structure)
14
+ MODEL_PATH = "model.pkl"
15
+ FEATURE_NAMES_PATH = "feature_names.json"
16
+
17
+ # Load model and features
18
+ model = None
19
+ feature_columns = None
20
+
21
+
22
+ def load_model():
23
+ """Load the trained model and feature columns"""
24
+ global model, feature_columns
25
+
26
+ if not os.path.exists(MODEL_PATH):
27
+ return False, f"Model not found at {MODEL_PATH}"
28
+
29
+ try:
30
+ model = joblib.load(MODEL_PATH)
31
+
32
+ # Load feature columns from JSON
33
+ if os.path.exists(FEATURE_NAMES_PATH):
34
+ with open(FEATURE_NAMES_PATH, 'r') as f:
35
+ feature_data = json.load(f)
36
+ feature_columns = feature_data.get('features', [])
37
+
38
+ return True, "Model loaded successfully"
39
+ except Exception as e:
40
+ return False, f"Error loading model: {str(e)}"
41
+
42
+
43
+ def preprocess_input(region, primary_role, alignment, status, species,
44
+ honour, ruthlessness, intelligence, combat_skill,
45
+ diplomacy, leadership, trait_loyal, trait_scheming):
46
+ """Preprocess input data to match training format"""
47
+
48
+ # Create input dictionary
49
+ input_dict = {
50
+ "honour_1to5": [honour],
51
+ "ruthlessness_1to5": [ruthlessness],
52
+ "intelligence_1to5": [intelligence],
53
+ "combat_skill_1to5": [combat_skill],
54
+ "diplomacy_1to5": [diplomacy],
55
+ "leadership_1to5": [leadership],
56
+ "trait_loyal": [1 if trait_loyal else 0],
57
+ "trait_scheming": [1 if trait_scheming else 0],
58
+ "trait_strategic": [0],
59
+ "trait_impulsive": [0],
60
+ "trait_charismatic": [0],
61
+ "trait_vengeful": [0],
62
+ "feature_set_version": [1],
63
+ "region": [region],
64
+ "primary_role": [primary_role],
65
+ "alignment": [alignment],
66
+ "status": [status],
67
+ "species": [species]
68
+ }
69
+
70
+ # Create DataFrame
71
+ df = pd.DataFrame(input_dict)
72
+
73
+ # One-hot encode categorical features
74
+ categorical_cols = ["region", "primary_role", "alignment", "status", "species"]
75
+ df_encoded = pd.get_dummies(df, columns=categorical_cols, drop_first=False)
76
+
77
+ # Align with training features
78
+ if feature_columns is not None:
79
+ # Add missing columns with 0
80
+ for col in feature_columns:
81
+ if col not in df_encoded.columns:
82
+ df_encoded[col] = 0
83
+ # Reorder columns to match training
84
+ df_encoded = df_encoded[feature_columns]
85
+
86
+ return df_encoded
87
+
88
+
89
+ def predict_house(region, primary_role, alignment, status, species,
90
+ honour, ruthlessness, intelligence, combat_skill,
91
+ diplomacy, leadership, trait_loyal, trait_scheming):
92
+ """
93
+ Predict house affiliation for a character
94
+
95
+ Returns:
96
+ str: Prediction result with house name and confidence
97
+ """
98
+ if model is None:
99
+ return "❌ Error: Model not loaded. Please contact the administrator."
100
+
101
+ try:
102
+ # Preprocess input
103
+ input_df = preprocess_input(
104
+ region, primary_role, alignment, status, species,
105
+ honour, ruthlessness, intelligence, combat_skill,
106
+ diplomacy, leadership, trait_loyal, trait_scheming
107
+ )
108
+
109
+ # Make prediction
110
+ prediction = model.predict(input_df)[0]
111
+
112
+ # Get prediction probability if available
113
+ result = f"🏰 **Predicted House: {prediction}**\n\n"
114
+
115
+ if hasattr(model, 'predict_proba'):
116
+ proba = model.predict_proba(input_df)[0]
117
+ confidence = max(proba)
118
+ result += f"📊 Confidence: {confidence:.2%}\n\n"
119
+
120
+ # Show top 3 probabilities
121
+ classes = model.classes_
122
+ proba_dict = dict(zip(classes, proba))
123
+ sorted_proba = sorted(proba_dict.items(), key=lambda x: x[1], reverse=True)[:3]
124
+
125
+ result += "**Top 3 Predictions:**\n"
126
+ for house, prob in sorted_proba:
127
+ result += f"- {house}: {prob:.2%}\n"
128
+
129
+ return result
130
+
131
+ except Exception as e:
132
+ return f"❌ Error during prediction: {str(e)}"
133
+
134
+
135
+ # Character attribute options
136
+ regions = [
137
+ "The North", "Crownlands", "Dorne", "Essos", "Iron Islands",
138
+ "King's Landing", "The Reach", "The Riverlands", "The Stormlands",
139
+ "The Vale", "The Westerlands", "Beyond the Wall"
140
+ ]
141
+
142
+ roles = [
143
+ "Commander", "Ruler", "Knight/Warrior", "Advisor", "Noble",
144
+ "Merchant/Noble", "Scholar/Healer", "Assassin/Spy", "Religious leader",
145
+ "Mage/Seer", "Commoner"
146
+ ]
147
+
148
+ alignments = [
149
+ "Lawful Good", "Neutral Good", "Chaotic Good",
150
+ "Lawful Neutral", "True Neutral", "Chaotic Neutral",
151
+ "Lawful Evil", "Neutral Evil", "Chaotic Evil"
152
+ ]
153
+
154
+ statuses = ["Alive", "Deceased", "Unknown/Varies"]
155
+
156
+ species_list = ["Human", "Warg", "White Walker"]
157
+
158
+
159
+ # Load model on startup
160
+ success, message = load_model()
161
+ if not success:
162
+ print(f"⚠️ Warning: {message}")
163
+
164
+
165
+ # Create Gradio interface
166
+ with gr.Blocks(title="Game of Thrones House Predictor", theme=gr.themes.Soft()) as demo:
167
+ gr.Markdown(
168
+ """
169
+ # 🏰 Game of Thrones House Predictor
170
+
171
+ Enter a character's attributes to predict which house they belong to!
172
+
173
+ This model was trained on Game of Thrones character data using **Azure Machine Learning** with **MLFlow tracking**.
174
+ The Decision Tree classifier analyzes character attributes, roles, and traits to predict house affiliation.
175
+ """
176
+ )
177
+
178
+ with gr.Row():
179
+ with gr.Column():
180
+ gr.Markdown("### 📍 Basic Information")
181
+ region = gr.Dropdown(choices=regions, label="Region", value="The North")
182
+ primary_role = gr.Dropdown(choices=roles, label="Primary Role", value="Commander")
183
+ alignment = gr.Dropdown(choices=alignments, label="Alignment", value="Lawful Good")
184
+ status = gr.Dropdown(choices=statuses, label="Status", value="Alive")
185
+ species = gr.Dropdown(choices=species_list, label="Species", value="Human")
186
+
187
+ with gr.Column():
188
+ gr.Markdown("### 📊 Attributes (1-5)")
189
+ honour = gr.Slider(minimum=1, maximum=5, step=1, value=4, label="Honour")
190
+ ruthlessness = gr.Slider(minimum=1, maximum=5, step=1, value=2, label="Ruthlessness")
191
+ intelligence = gr.Slider(minimum=1, maximum=5, step=1, value=3, label="Intelligence")
192
+ combat_skill = gr.Slider(minimum=1, maximum=5, step=1, value=4, label="Combat Skill")
193
+ diplomacy = gr.Slider(minimum=1, maximum=5, step=1, value=3, label="Diplomacy")
194
+ leadership = gr.Slider(minimum=1, maximum=5, step=1, value=4, label="Leadership")
195
+
196
+ with gr.Row():
197
+ gr.Markdown("### 🎭 Character Traits")
198
+
199
+ with gr.Row():
200
+ trait_loyal = gr.Checkbox(label="Loyal", value=True)
201
+ trait_scheming = gr.Checkbox(label="Scheming", value=False)
202
+
203
+ predict_btn = gr.Button("🔮 Predict House", variant="primary", size="lg")
204
+
205
+ output = gr.Markdown(label="Prediction Result")
206
+
207
+ # Examples
208
+ gr.Markdown("### 📝 Example Characters")
209
+ gr.Examples(
210
+ examples=[
211
+ ["The North", "Commander", "Lawful Good", "Alive", "Human", 4, 2, 3, 4, 3, 4, True, False],
212
+ ["King's Landing", "Ruler", "Neutral Evil", "Deceased", "Human", 2, 5, 4, 2, 3, 3, False, True],
213
+ ["The Reach", "Knight/Warrior", "Lawful Neutral", "Alive", "Human", 4, 3, 2, 5, 2, 3, True, False],
214
+ ["Essos", "Ruler", "Chaotic Good", "Alive", "Human", 3, 4, 4, 3, 4, 5, True, False],
215
+ ["The Westerlands", "Noble", "Lawful Evil", "Alive", "Human", 2, 5, 5, 3, 4, 4, False, True],
216
+ ],
217
+ inputs=[region, primary_role, alignment, status, species, honour, ruthlessness,
218
+ intelligence, combat_skill, diplomacy, leadership, trait_loyal, trait_scheming],
219
+ )
220
+
221
+ # Connect prediction function
222
+ predict_btn.click(
223
+ fn=predict_house,
224
+ inputs=[region, primary_role, alignment, status, species, honour, ruthlessness,
225
+ intelligence, combat_skill, diplomacy, leadership, trait_loyal, trait_scheming],
226
+ outputs=output
227
+ )
228
+
229
+ gr.Markdown(
230
+ """
231
+ ---
232
+ ### 📚 About This Model
233
+
234
+ **Training Pipeline:**
235
+ - Data source: Game of Thrones character dataset (100 characters)
236
+ - Algorithm: Decision Tree Classifier (scikit-learn)
237
+ - Training platform: Azure Machine Learning
238
+ - Experiment tracking: MLFlow
239
+ - Pipeline: Automated data preparation, training, and model registration
240
+
241
+ **Features Used:**
242
+ - **Geographic**: Region (12 regions across Westeros and Essos)
243
+ - **Role**: Primary character role (11 types)
244
+ - **Alignment**: D&D-style alignment (9 categories)
245
+ - **Attributes**: 6 numeric scores (honour, ruthlessness, intelligence, combat skill, diplomacy, leadership)
246
+ - **Traits**: Personality traits (loyal, scheming)
247
+
248
+ **Model Performance:**
249
+ - Trained with stratified train/test split
250
+ - Metrics logged: accuracy, precision, recall, F1-score (overall and per-class)
251
+ - Model registered and versioned in Azure ML Model Registry
252
+
253
+ ---
254
+
255
+ *Developed as part of an MLOps exam project demonstrating end-to-end ML pipeline deployment.*
256
+ """
257
+ )
258
+
259
+
260
+ if __name__ == "__main__":
261
+ demo.launch()
feature_names.json ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "features": [
3
+ "honour_1to5",
4
+ "ruthlessness_1to5",
5
+ "intelligence_1to5",
6
+ "combat_skill_1to5",
7
+ "diplomacy_1to5",
8
+ "leadership_1to5",
9
+ "trait_strategic",
10
+ "trait_impulsive",
11
+ "trait_charismatic",
12
+ "trait_vengeful",
13
+ "trait_loyal",
14
+ "trait_scheming",
15
+ "feature_set_version",
16
+ "region_Beyond the Wall",
17
+ "region_Crownlands",
18
+ "region_Dorne",
19
+ "region_Essos",
20
+ "region_Iron Islands",
21
+ "region_King's Landing",
22
+ "region_The North",
23
+ "region_The Reach",
24
+ "region_The Riverlands",
25
+ "region_The Stormlands",
26
+ "region_The Vale",
27
+ "region_The Westerlands",
28
+ "region_nan",
29
+ "primary_role_Advisor",
30
+ "primary_role_Assassin/Spy",
31
+ "primary_role_Commander",
32
+ "primary_role_Commoner",
33
+ "primary_role_Knight/Warrior",
34
+ "primary_role_Mage/Seer",
35
+ "primary_role_Merchant/Noble",
36
+ "primary_role_Religious leader",
37
+ "primary_role_Ruler",
38
+ "primary_role_Scholar/Healer",
39
+ "primary_role_nan",
40
+ "alignment_Chaotic Evil",
41
+ "alignment_Chaotic Good",
42
+ "alignment_Chaotic Neutral",
43
+ "alignment_Lawful Evil",
44
+ "alignment_Lawful Good",
45
+ "alignment_Lawful Neutral",
46
+ "alignment_Neutral Evil",
47
+ "alignment_Neutral Good",
48
+ "alignment_True Neutral",
49
+ "alignment_nan",
50
+ "status_Alive",
51
+ "status_Deceased",
52
+ "status_Unknown/Varies",
53
+ "status_nan",
54
+ "species_Human",
55
+ "species_Warg",
56
+ "species_White Walker",
57
+ "species_nan"
58
+ ]
59
+ }
model.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4b8b934dc8aacaa830ce2ab9d817d95d9cf497d5d8b1429c7ec82bddd2f9bddf
3
+ size 10121
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ gradio==4.44.0
2
+ pandas==2.1.4
3
+ scikit-learn==1.3.2
4
+ joblib==1.3.2