nirmitktripathii's picture
Deploy production model (pickle) and updated API
a043217
from flask import Flask, request, jsonify
from flask_cors import CORS
import numpy as np
import math
import pickle
import os
app = Flask(__name__)
CORS(app)
# Singleton Pattern for Model Loading
class ModelService:
_model = None
@classmethod
def get_model(cls):
if cls._model is None:
print("Loading Production Shot Quality Model (139MB)...")
# Path for HF Space/Docker environment
model_path = os.path.join(os.path.dirname(__file__), 'shot_quality_model.pickle')
if not os.path.exists(model_path):
# Fallback for local testing if path differs
model_path = 'shot_quality_model.pickle'
with open(model_path, 'rb') as f:
cls._model = pickle.load(f)
return cls._model
def calculate_features(x, y, shot_type):
# 1. Shot Distance (Euclidean to 100, 50)
dist = np.sqrt((100 - x) ** 2 + (50 - y) ** 2)
# 2. Shot Angle (Law of Cosines with posts at 100,46 and 100,54)
x2, y2 = 100, 46 # Left Post
x3, y3 = 100, 54 # Right Post
a = np.sqrt((x - x2)**2 + (y - y2)**2)
b = np.sqrt((x - x3)**2 + (y - y3)**2)
c = 8 # Distance between posts
denominator = 2 * a * b
if denominator == 0:
angle_deg = 0.0
else:
cos_angle = (a**2 + b**2 - c**2) / denominator
cos_angle = np.clip(cos_angle, -1.0, 1.0)
angle_rad = np.arccos(cos_angle)
angle_deg = (angle_rad * 180) / np.pi
# 3. Strong Foot Mapping (0: Weak, 1: Headers/Other, 2: Strong)
mapping = {
'RightFoot': 2,
'LeftFoot': 0,
'Head': 1,
'OtherBodyPart': 1
}
strong_foot = mapping.get(shot_type, 2)
return dist, angle_deg, strong_foot
@app.route('/predict', methods=['POST'])
def predict():
try:
data = request.get_json()
x = float(data.get('x'))
y = float(data.get('y'))
# Handle both shot_type and shotType
shot_type = data.get('shot_type') or data.get('shotType') or 'RightFoot'
dist, angle, strong_foot = calculate_features(x, y, shot_type)
features = np.array([[dist, angle, strong_foot]])
model = ModelService.get_model()
probability = model.predict_proba(features)[0][1]
return jsonify({
'shot_quality': float(probability),
'goal_prediction': 1 if probability > 0.5 else 0,
'features': {
'distance': float(dist),
'angle': float(angle),
'strong_foot': int(strong_foot)
}
})
except Exception as e:
import traceback
print(traceback.format_exc())
return jsonify({'error': str(e)}), 400
@app.route('/health', methods=['GET'])
def health():
return jsonify({'status': 'healthy', 'model_loaded': ModelService._model is not None})
@app.route('/', methods=['GET'])
def home():
return jsonify({
'name': 'Shot Quality xG API',
'status': 'online',
'endpoints': ['/predict', '/health']
})
if __name__ == '__main__':
port = int(os.environ.get('PORT', 8080))
# Pre-load model
ModelService.get_model()
app.run(host='0.0.0.0', port=port)