import joblib import tensorflow as tf from huggingface_hub import hf_hub_download import pandas as pd import numpy as np import warnings warnings.filterwarnings('ignore') # ========================================================== # 1. KONFIGURASI DAN PEMUATAN MODEL DARI HUGGING FACE HUB # ========================================================== REPO_ID = "hexselarchieles/koperasi-ml-models" def load_models_and_scalers(): """Mengunduh dan memuat semua model dan scaler dari Hugging Face Hub.""" print("Mulai mengunduh model dari Hugging Face Hub...") # --- Unduh dan Muat LightGBM Model (Joblib) --- lgbm_path = hf_hub_download(repo_id=REPO_ID, filename="lgbm_model.joblib") lgbm_model = joblib.load(lgbm_path) # --- Unduh dan Muat Scaler Statis (Joblib) --- scaler_static_path = hf_hub_download(repo_id=REPO_ID, filename="scaler_static.joblib") scaler_static = joblib.load(scaler_static_path) # --- Unduh dan Muat LSTM Model (H5) --- lstm_path = hf_hub_download(repo_id=REPO_ID, filename="lstm_model.h5") # PENTING: Gunakan compile=False untuk menghindari masalah dengan versi TensorFlow lstm_model = tf.keras.models.load_model(lstm_path, compile=False) # --- Unduh dan Muat Scaler Time Series (Joblib) --- scaler_ts_path = hf_hub_download(repo_id=REPO_ID, filename="scaler_ts.joblib") scaler_ts = joblib.load(scaler_ts_path) # --- Unduh dan Muat Blending Parameters --- blending_params_path = hf_hub_download(repo_id=REPO_ID, filename="blending_params.joblib") blending_params = joblib.load(blending_params_path) print("Semua model berhasil diunduh dan dimuat!") return lgbm_model, lstm_model, scaler_static, scaler_ts, blending_params # Pemuatan model terjadi saat server Gunicorn dimulai (Global Loading) try: LGBM_MODEL, LSTM_MODEL, SCALER_STATIC, SCALER_TS, BLENDING_PARAMS = load_models_and_scalers() except Exception as e: # Ini akan memicu Runtime Error di Gunicorn jika gagal print(f"FATAL ERROR DURING MODEL LOAD: {e}") raise e # ========================================================== # 2. FUNGSI UTAMA PRE-PROCESSING DAN PREDIKSI # ========================================================== # --- FUNGSI PLACEHOLDER: Anda harus menyesuaikan ini dengan fitur asli Anda --- def preprocess_static_data(data): """Contoh fungsi untuk membersihkan dan menstandarisasi data statis.""" df = pd.DataFrame([data]) # Ambil 20 fitur statis pertama (sesuaikan nama kolom Anda di sini) static_features = [col for col in df.columns if 'stat_' in col][:20] if not static_features: # Jika Anda tidak memiliki daftar fitur, ini akan menggunakan semua kolom numerik numeric_cols = df.select_dtypes(include=np.number).columns df_static = df[numeric_cols] else: df_static = df[static_features] # Melakukan Scaling menggunakan scaler statis yang sudah dimuat scaled_data = SCALER_STATIC.transform(df_static) return scaled_data def preprocess_ts_data(data): """Contoh fungsi untuk membersihkan dan menstandarisasi data time series.""" # Asumsi data time series adalah array 3D yang sudah bersih # Biasanya ini adalah data historis transaksi/kredit. # Ambil data time series dari input (misalnya, 'history') ts_data_raw = np.array(data.get('history', [[0]*10]*5)) # Melakukan Scaling menggunakan scaler time series yang sudah dimuat scaled_data = SCALER_TS.transform(ts_data_raw.reshape(-1, ts_data_raw.shape[-1])).reshape(ts_data_raw.shape) # LSTM membutuhkan bentuk (samples, timesteps, features) return np.expand_dims(scaled_data, axis=0) # ========================================================== # 3. FUNGSI UTAMA API (DIPANGGIL OLEH app.py) # ========================================================== def get_credit_score(raw_data): """ Memproses data, menjalankan prediksi dari kedua model, melakukan blending, dan menentukan keputusan akhir. """ print("Mulai memproses permintaan...") # --- 1. Pre-Processing --- lgbm_input = preprocess_static_data(raw_data) lstm_input = preprocess_ts_data(raw_data) # --- 2. Prediksi Model --- # Prediksi LightGBM (Output Skalar) lgbm_pred = LGBM_MODEL.predict(lgbm_input)[0] # Prediksi LSTM (Output Time Series, ambil nilai terakhir) lstm_output = LSTM_MODEL.predict(lstm_input, verbose=0) lstm_pred = lstm_output[0, -1, 0] # Ambil nilai prediksi terakhir # --- 3. Blending dan Final Score --- # Gunakan parameter blending yang sudah dimuat (BlENDIN_PARAMS adalah bobot) w_lgbm = BLENDING_PARAMS.get('w_lgbm', 0.5) w_lstm = BLENDING_PARAMS.get('w_lstm', 0.5) final_score = (w_lgbm * lgbm_pred) + (w_lstm * lstm_pred) # --- 4. Keputusan --- # Ganti 80 dengan threshold bisnis Anda if final_score >= 0.80: decision = "SETUJU" else: decision = "TOLAK" return { "score": float(final_score), "decision": decision }