File size: 3,270 Bytes
c4e8774
 
 
 
 
311ac82
c4e8774
b1de695
c4e8774
 
98aeab4
 
c4e8774
e572246
 
b1de695
 
e572246
 
 
 
 
 
 
 
 
b1de695
e572246
 
 
 
 
b1de695
 
e572246
e004797
 
b1de695
e004797
 
c4e8774
e572246
c4e8774
 
 
 
98aeab4
 
 
 
 
 
 
 
 
 
e004797
 
 
 
 
e572246
 
e004797
 
98aeab4
b1de695
98aeab4
 
 
b1de695
98aeab4
 
 
 
e572246
98aeab4
 
 
 
e572246
 
98aeab4
 
e572246
98aeab4
e004797
98aeab4
 
 
b1de695
e004797
98aeab4
b1de695
e004797
e572246
 
 
 
98aeab4
b1de695
98aeab4
 
b1de695
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
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
@st.cache_resource
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")