118 lines
3.8 KiB
Python
118 lines
3.8 KiB
Python
from flask import Flask, render_template, request, jsonify
|
|
import joblib
|
|
import sys
|
|
import traceback
|
|
import pandas as pd
|
|
import re
|
|
|
|
app = Flask(__name__)
|
|
|
|
# -----------------------------
|
|
# Load kamus CSV (delimiter ;)
|
|
# -----------------------------
|
|
kamus_df = pd.read_csv('kamus_normalize.csv', sep=';')
|
|
kamus_df.columns = kamus_df.columns.str.strip() # hilangkan spasi di nama kolom
|
|
kamus = dict(zip(kamus_df['BEFORE'], kamus_df['AFTER']))
|
|
|
|
# -----------------------------
|
|
# Preprocessing function
|
|
# -----------------------------
|
|
def preprocess(text):
|
|
text = text.lower()
|
|
for k, v in kamus.items():
|
|
text = text.replace(k, v)
|
|
text = re.sub(r'[^a-z\s]', '', text)
|
|
text = re.sub(r'\s+', ' ', text).strip()
|
|
return text
|
|
|
|
# -----------------------------
|
|
# Load model, vectorizer, LabelEncoder
|
|
# -----------------------------
|
|
try:
|
|
print("Python version:", sys.version)
|
|
|
|
print("Loading TF-IDF vectorizer...")
|
|
# Jika vectorizer pernah pakai custom analyzer, definisikan identity dulu:
|
|
# def identity(x): return x
|
|
vectorizer = joblib.load('tfidf_vectorizer.pkl')
|
|
print("Vectorizer loaded:", type(vectorizer))
|
|
|
|
print("Loading Naive Bayes model...")
|
|
model = joblib.load('nb_classifier.pkl')
|
|
print("Model loaded:", type(model))
|
|
|
|
print("Loading LabelEncoder...")
|
|
le = joblib.load('label_encoder.pkl')
|
|
print("LabelEncoder loaded:", type(le))
|
|
|
|
except FileNotFoundError as e:
|
|
print(f"Error: {e}")
|
|
raise
|
|
except Exception as e:
|
|
print(f"Error loading models: {str(e)}")
|
|
traceback.print_exc()
|
|
raise
|
|
|
|
# -----------------------------
|
|
# Routes
|
|
# -----------------------------
|
|
@app.route('/')
|
|
def home():
|
|
return render_template('index.html')
|
|
|
|
@app.route('/analyze', methods=['POST'])
|
|
def analyze():
|
|
if request.method == 'POST':
|
|
try:
|
|
text = request.form['text']
|
|
print(f"Received text: {text}")
|
|
|
|
# Preprocess input
|
|
text_clean = preprocess(text)
|
|
print(f"Preprocessed text: {text_clean}")
|
|
|
|
# Transform and predict
|
|
X = vectorizer.transform([text_clean])
|
|
pred_encoded = model.predict(X)[0]
|
|
pred_label = le.inverse_transform([pred_encoded])[0] # output string
|
|
print(f"Predicted label: {pred_label}")
|
|
|
|
# Get prediction probabilities
|
|
probs = model.predict_proba(X)[0]
|
|
|
|
# Ambil index probabilitas positif/negatif
|
|
labels = le.inverse_transform(range(len(probs))) # misal ['negatif', 'positif']
|
|
neg_idx = list(labels).index('negatif')
|
|
pos_idx = list(labels).index('positif')
|
|
|
|
# Map ke key JS yang sesuai
|
|
prob_percentages = {
|
|
'Positive': f"{probs[pos_idx]*100:.2f}%",
|
|
'Negative': f"{probs[neg_idx]*100:.2f}%"}
|
|
|
|
# Pastikan sentimen dikirim bahasa Inggris untuk JS
|
|
pred_label_lower = pred_label.lower().strip()
|
|
if pred_label_lower == 'positif':
|
|
sentiment_str = 'Positive'
|
|
else:
|
|
sentiment_str = 'Negative'
|
|
|
|
# Map probabilities to correct labels (hanya negatif/positif)
|
|
# label_order = le.inverse_transform(range(len(probs))) # ['negatif', 'positif']
|
|
# prob_percentages = {label.capitalize(): f"{prob*100:.2f}%" for label, prob in zip(label_order, probs)}
|
|
|
|
return jsonify({
|
|
'sentiment': pred_label.capitalize(),
|
|
'probabilities': prob_percentages
|
|
})
|
|
|
|
except Exception as e:
|
|
print(f"Error during analysis: {str(e)}")
|
|
traceback.print_exc()
|
|
return jsonify({'error': str(e)}), 500
|
|
|
|
# -----------------------------
|
|
# Run Flask
|
|
# -----------------------------
|
|
if __name__ == '__main__':
|
|
app.run(debug=True) |