import argparse import json import math import os import joblib import numpy as np import warnings # 경고 무시 (Feature name 관련 경고 제거) warnings.filterwarnings("ignore", category=UserWarning) # ========================================================= # 파일명 # ========================================================= FEATURES_FILENAME = "features.json" MODEL_FILENAME = "model_lgbm.pkl" SCALER_FILENAME = "scaler_lgbm.pkl" FEATURE_NAMES_FILENAME = "features_lgbm.txt" def safe_float(value): if value is None: return 0.0 x = float(value) return x if math.isfinite(x) else 0.0 def predict(working_dir: str, songno: str, feature: str = None): features_path = os.path.join(working_dir, FEATURES_FILENAME) if feature is None else feature model_path = os.path.join(working_dir, MODEL_FILENAME) scaler_path = os.path.join(working_dir, SCALER_FILENAME) feature_names_path = os.path.join(working_dir, FEATURE_NAMES_FILENAME) if not os.path.exists(model_path): raise FileNotFoundError(f"Model not found at {model_path}") model = joblib.load(model_path) scaler = joblib.load(scaler_path) with open(feature_names_path, "r", encoding="utf-8") as f: feature_names = [line.strip() for line in f.readlines() if line.strip()] with open(features_path, "r", encoding="utf-8") as f: data = json.load(f) targets = [item for item in data if str(item["songno"]) == str(songno)] if len(targets) == 0: raise ValueError(f"Chart not found: songno={songno}") results = [] for target in targets: row = [safe_float(target.get(k, 0)) for k in feature_names] X = np.array([row], dtype=np.float32) X = scaler.transform(X) pred = model.predict(X)[0] results.append({ "songno": str(songno), "diff": target.get("difficulty", "unknown"), "predicted": round(float(pred), 4) }) print(json.dumps(results, indent=2, ensure_ascii=False)) if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("--workingDir", required=True) parser.add_argument("--feature", required=False) parser.add_argument("--songno", required=True) args = parser.parse_args() predict(args.workingDir, args.songno, args.feature)