Spaces:
Sleeping
Sleeping
Download app.py from basaktamer/NLP_Disaster_Tweets: direct link, hf CLI and curl.
- Browser
- Download file 3.27 kB
-
https://huggingface.co/spaces/basaktamer/NLP_Disaster_Tweets/resolve/main/app.py
- Command line
-
hf download hf://spaces/basaktamer/NLP_Disaster_Tweets/app.py
-
curl -L -o app.py https://huggingface.co/spaces/basaktamer/NLP_Disaster_Tweets/resolve/main/app.py
3.27 kB
| import streamlit as st | |
| import pandas as pd | |
| import numpy as np | |
| import pickle | |
| import tensorflow as tf | |
| import neattext.functions as nfx | |
| from tensorflow.keras.models import load_model | |
| from tensorflow.keras.layers import InputLayer, Dense | |
| from PIL import Image | |
| # 1. Set Page Config | |
| st.set_page_config(page_title="Disaster Tweet Detector", page_icon="🚨", layout="centered") | |
| # 2. The Absolute Final Recovery Fix | |
| # We manually define the input shape (5000) to bypass the broken file metadata | |
| def load_assets(): | |
| # This function creates a dummy layer that Keras expects | |
| def fix_input_layer(**kwargs): | |
| # We force the shape to be 5000 because that's what your vectorizer produces | |
| return InputLayer(shape=(5000,)) | |
| # This dummy function ignores the Keras 3 'DTypePolicy' | |
| def fix_dtype(*args, **kwargs): | |
| return None | |
| custom_objects = { | |
| 'InputLayer': fix_input_layer, | |
| 'SafeInputLayer': fix_input_layer, | |
| 'DTypePolicy': fix_dtype, | |
| # If it complains about Dense again, we use the standard Dense | |
| 'Dense': Dense | |
| } | |
| # Load the model ignoring the 'compile' step and using our manual fixes | |
| model = load_model( | |
| 'disaster_model.h5', | |
| custom_objects=custom_objects, | |
| compile=False | |
| ) | |
| # Load the vectorizer | |
| with open('vectorizer.pkl', 'rb') as f: | |
| vect = pickle.load(f) | |
| return model, vect | |
| # 3. Preprocessing Function | |
| def clean_text(text): | |
| text = text.lower() | |
| text = nfx.remove_hashtags(text) | |
| text = nfx.remove_urls(text) | |
| text = nfx.remove_userhandles(text) | |
| text = nfx.remove_multiple_spaces(text) | |
| text = nfx.remove_special_characters(text) | |
| return text | |
| # --- App Interface --- | |
| try: | |
| model, vect = load_assets() | |
| except Exception as e: | |
| st.error(f"Critical Deployment Error: {e}") | |
| st.warning("Manual Override triggered. Please refresh the page.") | |
| st.stop() | |
| st.title("🚨 Disaster Tweet Detector") | |
| st.markdown("Analyzing social media sentiment for emergency response.") | |
| try: | |
| img = Image.open('disaster_wordcloud.png') | |
| st.image(img, caption="Common Disaster Keywords", use_container_width=True) | |
| except: | |
| pass | |
| st.subheader("Analyze a Tweet") | |
| user_input = st.text_area("Enter tweet text:", placeholder="e.g., Massive earthquake reported!") | |
| if st.button("Predict"): | |
| if user_input.strip() != "": | |
| cleaned_msg = clean_text(user_input) | |
| # Convert text to the 5000-feature vector | |
| vect_text = vect.transform([cleaned_msg]).toarray() | |
| # Prediction logic | |
| prediction = model.predict(vect_text) | |
| probability = float(prediction[0][0]) | |
| st.divider() | |
| if probability > 0.5: | |
| st.error(f"### ⚠️ Real Disaster Detected! ({probability:.2%})") | |
| st.progress(probability) | |
| else: | |
| st.success(f"### ✅ Normal Tweet ({(1-probability):.2%})") | |
| st.progress(1 - probability) | |
| with st.expander("Technical Details"): | |
| st.write(f"Processed Text: {cleaned_msg}") | |
| st.write(f"Vector Shape: {vect_text.shape}") | |
| else: | |
| st.warning("Please enter text.") | |
| st.divider() | |
| st.caption("Data Science Portfolio") |