Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,84 +1,110 @@
|
|
| 1 |
-
#
|
| 2 |
-
#
|
| 3 |
-
#
|
| 4 |
|
| 5 |
import gradio as gr
|
| 6 |
import joblib
|
| 7 |
-
import numpy as np
|
| 8 |
import shap
|
| 9 |
-
import
|
| 10 |
-
|
| 11 |
-
# -----------------------------------------------------
|
| 12 |
-
# β
Load Models and Vectorizers
|
| 13 |
-
# -----------------------------------------------------
|
| 14 |
-
english_model = joblib.load("best_model.pkl")
|
| 15 |
-
english_vectorizer = joblib.load("tfidf_vectorizer.pkl")
|
| 16 |
|
| 17 |
-
|
| 18 |
-
|
|
|
|
|
|
|
|
|
|
| 19 |
|
|
|
|
|
|
|
| 20 |
|
| 21 |
-
#
|
| 22 |
-
#
|
| 23 |
-
#
|
| 24 |
-
|
| 25 |
|
| 26 |
-
#
|
| 27 |
-
#
|
| 28 |
-
#
|
| 29 |
-
def predict_sentiment(text,
|
| 30 |
if not text.strip():
|
| 31 |
-
return "β οΈ Please enter some text
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
if lang == "English":
|
| 35 |
-
vectorizer = eng_vectorizer
|
| 36 |
model = eng_model
|
|
|
|
| 37 |
else:
|
| 38 |
-
vectorizer = per_vectorizer
|
| 39 |
model = per_model
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
|
|
|
|
|
|
|
|
|
| 83 |
if __name__ == "__main__":
|
| 84 |
-
|
|
|
|
|
|
| 1 |
+
# ===============================================================
|
| 2 |
+
# π Sentiment Analysis App β English & Persian (Gradio Deployment)
|
| 3 |
+
# ===============================================================
|
| 4 |
|
| 5 |
import gradio as gr
|
| 6 |
import joblib
|
|
|
|
| 7 |
import shap
|
| 8 |
+
import numpy as np
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
|
| 10 |
+
# ------------------------------------------------------------
|
| 11 |
+
# 1οΈβ£ Load pre-trained models and vectorizers
|
| 12 |
+
# ------------------------------------------------------------
|
| 13 |
+
eng_model = joblib.load("best_model.pkl")
|
| 14 |
+
eng_vectorizer = joblib.load("tfidf_vectorizer.pkl")
|
| 15 |
|
| 16 |
+
per_model = joblib.load("logistic_regression.pkl")
|
| 17 |
+
per_vectorizer = joblib.load("tfidf_vectorizer_persian.pkl")
|
| 18 |
|
| 19 |
+
# ------------------------------------------------------------
|
| 20 |
+
# 2οΈβ£ Define class labels
|
| 21 |
+
# ------------------------------------------------------------
|
| 22 |
+
class_names = ["Negative", "Neutral", "Positive"]
|
| 23 |
|
| 24 |
+
# ------------------------------------------------------------
|
| 25 |
+
# 3οΈβ£ Prediction Function
|
| 26 |
+
# ------------------------------------------------------------
|
| 27 |
+
def predict_sentiment(text, language):
|
| 28 |
if not text.strip():
|
| 29 |
+
return "β οΈ Please enter some text!", None, None
|
| 30 |
+
|
| 31 |
+
if language == "English":
|
|
|
|
|
|
|
| 32 |
model = eng_model
|
| 33 |
+
vectorizer = eng_vectorizer
|
| 34 |
else:
|
|
|
|
| 35 |
model = per_model
|
| 36 |
+
vectorizer = per_vectorizer
|
| 37 |
+
|
| 38 |
+
# Vectorize input
|
| 39 |
+
vec = vectorizer.transform([text])
|
| 40 |
+
probs = model.predict_proba(vec)[0]
|
| 41 |
+
pred_class = np.argmax(probs)
|
| 42 |
+
label = class_names[pred_class]
|
| 43 |
+
confidence = probs[pred_class]
|
| 44 |
+
|
| 45 |
+
# Interpret top words with SHAP
|
| 46 |
+
explainer = shap.Explainer(model, vectorizer.transform(["sample"]))
|
| 47 |
+
feature_names = vectorizer.get_feature_names_out()
|
| 48 |
+
shap_values = explainer(vec)
|
| 49 |
+
|
| 50 |
+
# top contributing words
|
| 51 |
+
shap_vals = shap_values[0].values[:, pred_class]
|
| 52 |
+
top_indices = np.argsort(-np.abs(shap_vals))[:10]
|
| 53 |
+
top_words = [feature_names[i] for i in top_indices]
|
| 54 |
+
top_contribs = shap_vals[top_indices]
|
| 55 |
+
|
| 56 |
+
interpretation = {
|
| 57 |
+
"words": top_words,
|
| 58 |
+
"contributions": top_contribs.tolist()
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
return f"π― **{label}** (confidence: {confidence:.2f})", probs.tolist(), interpretation
|
| 62 |
|
| 63 |
+
|
| 64 |
+
# ------------------------------------------------------------
|
| 65 |
+
# 4οΈβ£ Gradio Interface
|
| 66 |
+
# ------------------------------------------------------------
|
| 67 |
+
def gradio_ui(text, language):
|
| 68 |
+
pred, probs, interp = predict_sentiment(text, language)
|
| 69 |
+
|
| 70 |
+
if not probs:
|
| 71 |
+
return pred, None, None
|
| 72 |
+
|
| 73 |
+
# Confidence Bar Plot
|
| 74 |
+
bar_plot = {cls: float(p) for cls, p in zip(class_names, probs)}
|
| 75 |
+
|
| 76 |
+
# Word Contribution Table
|
| 77 |
+
word_table = None
|
| 78 |
+
if interp:
|
| 79 |
+
word_table = {
|
| 80 |
+
"Word": interp["words"],
|
| 81 |
+
"SHAP Impact": interp["contributions"]
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
return pred, bar_plot, word_table
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
# ------------------------------------------------------------
|
| 88 |
+
# 5οΈβ£ Gradio Layout
|
| 89 |
+
# ------------------------------------------------------------
|
| 90 |
+
with gr.Blocks(theme=gr.themes.Soft()) as interface:
|
| 91 |
+
gr.Markdown("## π Sentiment Analysis (English & Persian)
|
| 92 |
+
Select language, enter text, and view predictions with interpretable SHAP insights!")
|
| 93 |
+
|
| 94 |
+
lang = gr.Radio(["English", "Persian"], label="Select Dataset", value="English")
|
| 95 |
+
text = gr.Textbox(label="Enter your text here", placeholder="Type an English or Persian comment...")
|
| 96 |
+
|
| 97 |
+
output_pred = gr.Markdown(label="Prediction")
|
| 98 |
+
output_bar = gr.BarPlot(label="Confidence per Class")
|
| 99 |
+
output_table = gr.Dataframe(label="Top Influential Words", headers=["Word", "SHAP Impact"])
|
| 100 |
+
|
| 101 |
+
btn = gr.Button("π Analyze Sentiment")
|
| 102 |
+
|
| 103 |
+
btn.click(fn=gradio_ui, inputs=[text, lang], outputs=[output_pred, output_bar, output_table])
|
| 104 |
+
|
| 105 |
+
# ------------------------------------------------------------
|
| 106 |
+
# 6οΈβ£ Launch App
|
| 107 |
+
# ------------------------------------------------------------
|
| 108 |
if __name__ == "__main__":
|
| 109 |
+
interface.launch(share=True)
|
| 110 |
+
|