import os import joblib # ========================================================= # KONFIGURASI MODEL # ========================================================= BASE_DIR = os.path.dirname( os.path.dirname( os.path.abspath(__file__) ) ) MODEL_DIR = os.path.join( BASE_DIR, "models" ) MODEL_PATH = os.path.join( MODEL_DIR, "model_naive_bayes.pkl" ) # ========================================================= # LOAD MODEL # ========================================================= if not os.path.exists(MODEL_PATH): raise FileNotFoundError( f"Model tidak ditemukan: {MODEL_PATH}" ) try: model_final = joblib.load(MODEL_PATH) except Exception as e: raise RuntimeError( f"Gagal memuat model: {str(e)}" ) # ========================================================= # VALIDASI PIPELINE # ========================================================= if not hasattr(model_final, "named_steps"): raise ValueError( "Model harus berupa Pipeline " "TF-IDF + MultinomialNB." ) # Pastikan step TF-IDF tersedia if "tfidf" not in model_final.named_steps: raise ValueError( "Pipeline tidak memiliki step 'tfidf'." ) # Pastikan step Naïve Bayes tersedia if "nb" not in model_final.named_steps: raise ValueError( "Pipeline tidak memiliki step 'nb'." ) # ========================================================= # AMBIL KOMPONEN MODEL # ========================================================= tfidf_vectorizer = model_final.named_steps["tfidf"] nb_model = model_final.named_steps["nb"] # ========================================================= # PREDIKSI SENTIMEN # ========================================================= def predict_sentiment(text): if not text or not str(text).strip(): raise ValueError( "Teks komentar tidak boleh kosong." ) text = str(text).strip() # Prediksi prediction = model_final.predict([text])[0] # Probabilitas probabilities = model_final.predict_proba([text])[0] # Konversi label sentiment = ( "Positif" if int(prediction) == 1 else "Negatif" ) # Probabilitas kelas yang diprediksi probability = float( probabilities[ list(model_final.classes_).index(prediction) ] ) return { "label": int(prediction), "sentiment": sentiment, "probability": round( probability, 6 ) } # ========================================================= # TF-IDF SATU KOMENTAR # ========================================================= def get_tfidf(text): if not text or not str(text).strip(): return [] text = str(text).strip() # Transform menggunakan vectorizer # yang SUDAH FIT dari model final vector = tfidf_vectorizer.transform( [text] ) feature_names = ( tfidf_vectorizer .get_feature_names_out() ) hasil = [] # Karena sparse matrix, # ambil hanya fitur yang nilainya > 0 row = vector[0] for col_index, nilai in zip( row.indices, row.data ): hasil.append({ "kata": feature_names[col_index], "nilai": round( float(nilai), 6 ) }) # Urutkan berdasarkan nilai TF-IDF terbesar hasil.sort( key=lambda x: x["nilai"], reverse=True ) return hasil