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 "
⚠️ Please enter some text.
" try: # Check if models are loaded if model_components is None: return "
❌ Model not loaded. Check logs.
" model = model_components["model"] vectorizer = model_components["vectorizer"] label_encoder = model_components["label_encoder"] # Check if vectorizer exists if vectorizer is None: return "
❌ Vectorizer not available
" # 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"""
{category['emoji']}
{category['text']}
Confidence: {score:.2%}
""" else: # Cyberbullying message return f"""
{category['emoji']}
{category['text']}
{label}
Confidence: {score:.2%}
""" except Exception as e: import traceback error_msg = traceback.format_exc() print(f"ERROR in prediction: {str(e)}") print(error_msg) return f"
❌ Error: {str(e)}
" with gr.Blocks(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("
🛡️ Cyberbullying Detection System
") gr.Markdown("
End-to-end NLP system for detecting cyberbullying, including religion-based abuse
") 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()