Daizzyy's picture
Update app.py
7edacbb verified
import gradio as gr
import joblib
import os
def load_model():
"""Load model from local files in the Space"""
try:
print("Loading model from local files...")
print("\nFiles in current directory:")
for f in os.listdir("."):
if f.endswith((".jobilib", ".pkl", ".txt")):
print(f" - {f}")
model_files = [
"tfidf_logreg_best.jobilib",
"model.jobilib",
"model.pkl"
]
model = None
for mf in model_files:
if os.path.exists(mf):
print(f"\nLoading model: {mf}")
model = joblib.load(mf)
print(f"✅ Model loaded from {mf}")
break
if model is None:
print("❌ No model file found!")
return None
vectorizer_files = [
"vocab.txt",
"vocab",
"vectorizer.jobilib",
"tfidf.jobilib"
]
vectorizer = None
for vf in vectorizer_files:
if os.path.exists(vf):
print(f"Loading vectorizer: {vf}")
vectorizer = joblib.load(vf)
print(f"✅ Vectorizer loaded from {vf}")
break
if vectorizer is None:
print("⚠️ Vectorizer not found")
# Try to load label encoder
label_encoder = None
if os.path.exists("label_encoder.jobilib"):
print("Loading label encoder...")
label_encoder = joblib.load("label_encoder.jobilib")
print("✅ Label encoder loaded")
return {
"model": model,
"vectorizer": vectorizer,
"label_encoder": label_encoder
}
except Exception as e:
print(f"❌ Error loading model: {str(e)}")
import traceback
print(traceback.format_exc())
return None
# Load model on startup
print("Starting model loading...")
model_components = load_model()
if model_components is None:
print("⚠️ Model loading failed!")
else:
print("✅ All models loaded successfully!")
def predict(text):
"""Predict cyberbullying category"""
if not text.strip():
return "<div class='warn'>⚠️ Please enter some text.</div>"
try:
# Check if models are loaded
if model_components is None:
return "<div class='warn'>❌ Model not loaded. Check logs.</div>"
model = model_components["model"]
vectorizer = model_components["vectorizer"]
label_encoder = model_components["label_encoder"]
# Check if vectorizer exists
if vectorizer is None:
return "<div class='warn'>❌ Vectorizer not available</div>"
# Vectorize the input text
text_vector = vectorizer.transform([text])
# Get prediction
prediction = model.predict(text_vector)[0]
# Get confidence score
try:
probabilities = model.predict_proba(text_vector)[0]
score = max(probabilities)
except:
score = 0.8
# Decode label if encoder exists
if label_encoder is not None:
try:
label = label_encoder.inverse_transform([prediction])[0]
except:
label = str(prediction)
else:
label = str(prediction)
print(f"Prediction: {label}, Score: {score:.4f}")
# Category definitions
cyberbullying_types = {
"age": {"emoji": "👶", "color": "#ff6b6b", "text": "Age-Based Cyberbullying"},
"gender": {"emoji": "⚥️", "color": "#ff8c42", "text": "Gender-Based Cyberbullying"},
"ethnicity": {"emoji": "🌍", "color": "#ffa502", "text": "Ethnicity-Based Cyberbullying"},
"religion": {"emoji": "🙏", "color": "#ff6b9d", "text": "Religion-Based Cyberbullying"},
"other_cyberbullying": {"emoji": "⚠️", "color": "#ff4757", "text": "Other Cyberbullying Detected"},
"not_cyberbullying": {"emoji": "✅", "color": "#00ff64", "text": "Safe Message"}
}
# Get category info
label_lower = str(label).lower().strip()
category = cyberbullying_types.get(
label_lower,
cyberbullying_types.get(label, cyberbullying_types["not_cyberbullying"])
)
# Safe message
if label_lower == "not_cyberbullying":
return f"""
<div class='safe'>
<div class='checkmark'>{category['emoji']}</div>
<div class='safe-text'>{category['text']}</div>
<div class='confidence-bar'>
<div class='confidence-fill safe-fill' style='width: {score*100}%'></div>
</div>
<span class='confidence-score'>Confidence: {score:.2%}</span>
</div>
"""
else:
# Cyberbullying message
return f"""
<div class='bully'>
<div class='warning-icon'>{category['emoji']}</div>
<div class='bully-text'>{category['text']}</div>
<div class='label-badge' style='background: {category["color"]}33; border-color: {category["color"]};'>{label}</div>
<div class='confidence-bar'>
<div class='confidence-fill bully-fill' style='width: {score*100}%; background: {category["color"]};'></div>
</div>
<span class='confidence-score'>Confidence: {score:.2%}</span>
</div>
"""
except Exception as e:
import traceback
error_msg = traceback.format_exc()
print(f"ERROR in prediction: {str(e)}")
print(error_msg)
return f"<div class='warn'>❌ Error: {str(e)}</div>"
with gr.Blocks(css="""
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"/>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body {
background: linear-gradient(-45deg, #7d00ff, #5500ff, #4b7fff, #0099ff, #00bfff);
background-size: 500% 500%;
animation: gradientBG 15s ease infinite;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
min-height: 100vh;
}
@keyframes gradientBG {
0% {background-position: 0% 50%;}
25% {background-position: 100% 50%;}
50% {background-position: 100% 100%;}
75% {background-position: 0% 100%;}
100% {background-position: 0% 50%;}
}
.gradio-container {
background: rgba(20, 20, 40, 0.85) !important;
border-radius: 25px !important;
box-shadow: 0 25px 80px rgba(0, 0, 0, 0.4), inset 0 0 30px rgba(255, 255, 255, 0.1) !important;
backdrop-filter: blur(15px) !important;
border: 1px solid rgba(255, 255, 255, 0.15) !important;
padding: 40px !important;
}
.title {
font-size: 52px;
font-weight: 900;
text-align: center;
background: linear-gradient(135deg, #7d00ff, #5500ff, #4b7fff, #0099ff);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
animation: slideInDown 1s ease-out, glow 3s ease-in-out infinite;
margin-bottom: 10px;
}
@keyframes slideInDown {
from {
opacity: 0;
transform: translateY(-50px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes glow {
0%, 100% {
text-shadow: 0 0 20px rgba(125, 0, 255, 0.5), 0 0 40px rgba(75, 127, 255, 0.3);
}
50% {
text-shadow: 0 0 30px rgba(75, 127, 255, 0.6), 0 0 60px rgba(0, 153, 255, 0.4);
}
}
.subtitle {
text-align: center;
color: #e0e0ff;
margin-bottom: 30px;
font-style: italic;
font-size: 16px;
animation: fadeInUp 1s ease-out 0.2s both;
letter-spacing: 1px;
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
textarea {
background: rgba(255, 255, 255, 0.08) !important;
border: 2px solid rgba(75, 127, 255, 0.3) !important;
border-radius: 15px !important;
padding: 18px !important;
font-size: 16px !important;
color: #e0e0ff !important;
transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) !important;
box-shadow: 0 8px 32px rgba(75, 127, 255, 0.1), inset 0 0 20px rgba(255, 255, 255, 0.05) !important;
backdrop-filter: blur(10px) !important;
}
textarea::placeholder {
color: rgba(224, 224, 255, 0.5) !important;
}
textarea:focus {
border-color: #0099ff !important;
box-shadow: 0 15px 50px rgba(0, 153, 255, 0.4), inset 0 0 30px rgba(0, 153, 255, 0.1) !important;
transform: translateY(-5px) scale(1.02);
}
.btn-primary {
background: linear-gradient(135deg, #7d00ff, #5500ff, #4b7fff, #0099ff) !important;
background-size: 300% 300% !important;
border: 2px solid rgba(75, 127, 255, 0.5) !important;
color: white !important;
font-weight: 700 !important;
font-size: 16px !important;
padding: 14px 40px !important;
border-radius: 50px !important;
cursor: pointer !important;
transition: all 0.4s ease !important;
box-shadow: 0 10px 40px rgba(75, 127, 255, 0.4) !important;
animation: bounceIn 0.8s cubic-bezier(0.68, -0.55, 0.265, 1.55) 0.4s both;
position: relative;
overflow: hidden;
}
@keyframes bounceIn {
0% {
opacity: 0;
transform: scale(0.1) rotateZ(-45deg);
}
50% {
opacity: 1;
transform: scale(1.1) rotateZ(10deg);
}
100% {
transform: scale(1) rotateZ(0deg);
}
}
.btn-primary:hover {
transform: translateY(-5px) scale(1.05);
box-shadow: 0 20px 60px rgba(0, 153, 255, 0.6) !important;
background-position: 100% 0 !important;
}
.btn-primary:active {
transform: translateY(-2px) scale(0.98);
}
.safe {
background: linear-gradient(135deg, rgba(0, 255, 100, 0.15), rgba(100, 255, 150, 0.08));
border: 2px solid rgba(0, 255, 100, 0.4);
padding: 35px;
border-radius: 20px;
color: #00ff64;
text-align: center;
animation: slideInRight 0.8s cubic-bezier(0.34, 1.56, 0.64, 1), cardGlowGreen 3s ease-in-out infinite;
box-shadow: 0 20px 60px rgba(0, 255, 100, 0.25);
backdrop-filter: blur(15px);
}
.bully {
background: linear-gradient(135deg, rgba(255, 0, 0, 0.15), rgba(255, 100, 100, 0.08));
border: 2px solid rgba(255, 107, 107, 0.4);
padding: 35px;
border-radius: 20px;
color: #ff6b6b;
text-align: center;
animation: slideInRight 0.8s cubic-bezier(0.34, 1.56, 0.64, 1), cardGlowRed 2s ease-in-out infinite;
box-shadow: 0 20px 60px rgba(255, 107, 107, 0.25);
backdrop-filter: blur(15px);
}
@keyframes slideInRight {
from {
opacity: 0;
transform: translateX(100px) rotateY(20deg);
}
to {
opacity: 1;
transform: translateX(0) rotateY(0deg);
}
}
@keyframes cardGlowGreen {
0%, 100% {
box-shadow: 0 20px 60px rgba(0, 255, 100, 0.25);
}
50% {
box-shadow: 0 30px 80px rgba(0, 255, 100, 0.4);
}
}
@keyframes cardGlowRed {
0%, 100% {
box-shadow: 0 20px 60px rgba(255, 107, 107, 0.25);
}
50% {
box-shadow: 0 30px 80px rgba(255, 107, 107, 0.4);
}
}
.warn {
color: #ffb700;
text-align: center;
font-weight: 700;
font-size: 18px;
animation: shake 0.5s ease-in-out;
padding: 20px;
}
@keyframes shake {
0%, 100% {transform: translateX(0);}
10%, 30%, 50%, 70%, 90% {transform: translateX(-8px);}
20%, 40%, 60%, 80% {transform: translateX(8px);}
}
.checkmark, .warning-icon {
font-size: 56px;
margin-bottom: 15px;
animation: bounce 0.8s cubic-bezier(0.68, -0.55, 0.265, 1.55);
display: inline-block;
}
@keyframes bounce {
0% {
opacity: 0;
transform: scale(0) rotateZ(-45deg);
}
50% {
transform: scale(1.2) rotateZ(15deg);
}
100% {
opacity: 1;
transform: scale(1) rotateZ(0deg);
}
}
.safe-text, .bully-text {
font-size: 28px;
font-weight: 800;
margin-bottom: 15px;
animation: fadeInDown 0.8s ease-out 0.2s both;
}
.label-badge {
display: inline-block;
background: rgba(255, 107, 107, 0.2);
border: 2px solid rgba(255, 107, 107, 0.5);
padding: 10px 20px;
border-radius: 25px;
margin-bottom: 18px;
font-size: 14px;
font-weight: 700;
animation: zoomIn 0.7s ease-out 0.3s both;
}
@keyframes zoomIn {
from {
opacity: 0;
transform: scale(0.3);
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes fadeInDown {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.confidence-bar {
width: 100%;
height: 10px;
background: rgba(255, 255, 255, 0.1);
border-radius: 12px;
margin-bottom: 15px;
overflow: hidden;
animation: fadeIn 0.8s ease-out 0.1s both;
border: 1px solid rgba(255, 255, 255, 0.2);
}
.confidence-fill {
height: 100%;
border-radius: 12px;
transition: width 1.2s cubic-bezier(0.34, 1.56, 0.64, 1);
animation: fillWidth 1.2s ease-out;
}
@keyframes fillWidth {
from {
width: 0 !important;
}
}
.safe-fill {
background: linear-gradient(90deg, #00ff64, #00d452);
box-shadow: 0 0 25px rgba(0, 255, 100, 0.8);
}
.bully-fill {
background: linear-gradient(90deg, #ff6b6b, #ff4444);
box-shadow: 0 0 25px rgba(255, 107, 107, 0.8);
}
.confidence-score {
font-size: 15px;
opacity: 0.9;
animation: fadeIn 0.8s ease-out 0.4s both;
font-weight: 600;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@media (max-width: 768px) {
.title {
font-size: 36px;
}
.safe, .bully {
padding: 25px;
}
}
""") as demo:
gr.Markdown("<div class='title'>🛡️ Cyberbullying Detection System</div>")
gr.Markdown("<div class='subtitle'>End-to-end NLP system for detecting cyberbullying, including religion-based abuse</div>")
with gr.Group():
text_input = gr.Textbox(
lines=4,
placeholder="Enter a message to analyze...",
label="Input Text"
)
detect_btn = gr.Button("🔍 Detect", variant="primary")
output = gr.HTML()
detect_btn.click(
fn=predict,
inputs=text_input,
outputs=output
)
if __name__ == "__main__":
demo.launch()