Spaces:
Sleeping
Sleeping
File size: 10,423 Bytes
f9903ea 9739fd6 f9903ea 95fe581 7c483c8 40b7a7a c70917b 9739fd6 f9903ea 40b7a7a 7c483c8 40b7a7a 7c483c8 40b7a7a 48034cd 7c483c8 40b7a7a 7c483c8 40b7a7a 48034cd 7c483c8 40b7a7a 48034cd 7a0022c 7c483c8 95fe581 7c483c8 40b7a7a 7d63c56 40b7a7a 7d63c56 f9903ea 40b7a7a bfc5779 40b7a7a 7c483c8 40b7a7a 48034cd 40b7a7a 48034cd 40b7a7a 48034cd 7c483c8 40b7a7a 345319f 7c483c8 40b7a7a 7c483c8 345319f f9903ea 7c483c8 7f5130a 7d63c56 7c483c8 7f5130a bfc5779 7c483c8 345319f bfc5779 95fe581 6f7d2fb 40b7a7a 1138fa8 48034cd 6f7d2fb 40b7a7a 7a0022c 1138fa8 48034cd 6f7d2fb 7a0022c 40b7a7a 7a0022c 6f7d2fb 7a0022c 1138fa8 48034cd 7a0022c 1138fa8 95fe581 48034cd 7a0022c 40b7a7a 7a0022c 48034cd 7a0022c 1138fa8 48034cd 40b7a7a 48034cd 40b7a7a 48034cd 40b7a7a 48034cd 40b7a7a 48034cd 40b7a7a 48034cd 40b7a7a 48034cd 40b7a7a 6f7d2fb 40b7a7a 305441b 40b7a7a bfc5779 40b7a7a 345319f bfc5779 6f7d2fb 48034cd b4fad3e bfc5779 40b7a7a 345319f bfc5779 345319f 48034cd bfc5779 40b7a7a 345319f bfc5779 345319f 48034cd bfc5779 40b7a7a 305441b 48034cd 1138fa8 7a0022c 48034cd 40b7a7a 48034cd 40b7a7a 48034cd fbd79d5 40b7a7a fbd79d5 40b7a7a fbd79d5 40b7a7a fbd79d5 95fe581 fbd79d5 7a0022c |
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 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
import streamlit as st
from transformers import pipeline, AutoModelForSequenceClassification, AutoTokenizer
import torch
import numpy as np
# Function to analyze email for spam and sentiment
def analyze_email(email_body):
# Load pre-trained models: spam detection and sentiment analysis
spam_pipeline = pipeline("text-classification", model="cybersectony/phishing-email-detection-distilbert_v2.4.1")
sentiment_model = AutoModelForSequenceClassification.from_pretrained("ISOM5240GP4/email_sentiment", num_labels=2)
tokenizer = AutoTokenizer.from_pretrained("distilbert-base-uncased")
# Step 1: Check if the email is spam using the spam detection model
spam_result = spam_pipeline(email_body)
spam_label = spam_result[0]["label"] # LABEL_1 indicates spam
spam_confidence = spam_result[0]["score"]
if spam_label == "LABEL_1":
# If spam, return type "spam" and a message indicating no follow-up
return "spam", f"This is a spam email (Confidence: {spam_confidence:.2f}). No follow-up needed."
else:
# Step 2: For non-spam emails, analyze sentiment (positive/negative)
inputs = tokenizer(email_body, padding=True, truncation=True, return_tensors='pt') # Tokenize input
outputs = sentiment_model(**inputs) # Get model predictions
predictions = torch.nn.functional.softmax(outputs.logits, dim=-1) # Apply softmax for probabilities
predictions = predictions.cpu().detach().numpy() # Convert to numpy array
sentiment_index = np.argmax(predictions) # Get the predicted sentiment (0 = negative, 1 = positive)
sentiment_confidence = predictions[0][sentiment_index]
sentiment = "Positive" if sentiment_index == 1 else "Negative"
if sentiment == "Positive":
# If positive sentiment, no follow-up needed
return "positive", (f"This email is not spam (Confidence: {spam_confidence:.2f}).\n"
f"Sentiment: {sentiment} (Confidence: {sentiment_confidence:.2f}). No follow-up needed.")
else:
# If negative sentiment, mark as needing follow-up with bolded text
return "negative", (f"This email is not spam (Confidence: {spam_confidence:.2f}).\n"
f"Sentiment: {sentiment} (Confidence: {sentiment_confidence:.2f}).\n"
"<b>Need to Follow-Up</b>: This email is not spam and has negative sentiment.")
# Main application function
def main():
# Set the app title to the project name
st.title("EmailSentry")
# Display the project objective
st.write("Aims to perform analysis on incoming emails and to determine whether there is urgency or higher priority for the company to follow-up.")
# Initialize session state to store email input and analysis results
if "email_body" not in st.session_state:
st.session_state.email_body = "" # Holds the email text
if "result" not in st.session_state:
st.session_state.result = "" # Stores the analysis result text
if "result_type" not in st.session_state:
st.session_state.result_type = "" # Tracks result type (spam, positive, negative)
# Add collapsible instructions for user guidance
with st.expander("How to Use", expanded=False):
st.write("""
- Type or paste an email into the text box.
- Alternatively, click one of the sample buttons to load a predefined email.
- Press 'Analyze Email' to check if it’s spam and analyze its sentiment.
- Use 'Clear' to reset the input and result.
""")
# Text area where users input or view the email body
email_body = st.text_area("Email Body", value=st.session_state.email_body, height=200, key="email_input")
# Define sample emails and their snippets for example buttons
sample_spam = """
Subject: Urgent: Verify Your Account Now!
Dear Customer,
We have detected unusual activity on your account. To prevent suspension, please verify your login details immediately by clicking the link below:
[Click Here to Verify](http://totally-legit-site.com/verify)
Failure to verify within 24 hours will result in your account being locked. This is for your security.
Best regards,
The Security Team
"""
spam_snippet = "Subject: Urgent: Verify Your Account Now! Dear Customer, We have detected unusual activity..."
sample_not_spam_positive = """
Subject: Great Experience with HKTV mall
Dear Sir,
I just received my order and I’m really impressed with the speed of the delivery. Keep up the good work.
Best regards,
Emily
"""
positive_snippet = "Subject: Great Experience with HKTV mall Dear Sir, I just received my order and I’m really..."
sample_not_spam_negative = """
Subject: Issue with Recent Delivery
Dear Support,
I received my package today, but it was damaged, and two items were missing. This is really frustrating—please let me know how we can resolve this as soon as possible.
Thanks,
Sarah
"""
negative_snippet = "Subject: Issue with Recent Delivery Dear Support, I received my package today, but..."
# Custom CSS for styling buttons and result boxes
st.markdown("""
<style>
/* Style for sample buttons (smaller, light gray) */
div.stButton > button[kind="secondary"]:not([key="clear"]) {
font-size: 12px;
padding: 5px 10px;
background-color: #f0f0f0;
color: #333333;
border: 1px solid #cccccc;
border-radius: 3px;
}
/* Analyze Email button (orange, matches Clear button size) */
div.stButton > button[key="analyze"] {
background-color: #FF5733 !important; /* Force orange color */
color: white !important;
font-size: 18px;
padding: 12px 24px;
border: none;
border-radius: 5px;
width: 100%;
height: 50px;
box-sizing: border-box;
text-align: center;
}
div.stButton > button[key="analyze"]:hover {
background-color: #E74C3C !important; /* Darker orange on hover */
}
/* Clear button (gray, aligned with Analyze) */
div.stButton > button[key="clear"] {
background-color: #d3d3d3 !important; /* Force gray color */
color: #333333 !important;
font-size: 18px;
padding: 12px 24px;
border: none;
border-radius: 5px;
width: 100%;
height: 50px;
box-sizing: border-box;
text-align: center;
}
div.stButton > button[key="clear"]:hover {
background-color: #b0b0b0 !important; /* Darker gray on hover */
}
/* Result boxes with updated colors */
.spam-result {
background-color: #ff3333; /* Red for no follow-up (spam) */
color: white;
padding: 10px;
border-radius: 5px;
border: 1px solid #cc0000;
}
.positive-result {
background-color: #ff3333; /* Red for no follow-up (positive) */
color: white;
padding: 10px;
border-radius: 5px;
border: 1px solid #cc0000;
}
.negative-result {
background-color: #006633; /* Dark green for follow-up needed */
color: white;
padding: 10px;
border-radius: 5px;
border: 1px solid #004d26;
}
</style>
""", unsafe_allow_html=True)
# Subheading to label the sample email buttons
st.subheader("Examples")
# Layout for sample buttons in 3 columns
col1, col2, col3 = st.columns(3)
with col1:
# Button to load spam sample
if st.button(spam_snippet, key="spam_sample"):
st.session_state.email_body = sample_spam
st.session_state.result = ""
st.session_state.result_type = ""
st.rerun()
with col2:
# Button to load positive non-spam sample
if st.button(positive_snippet, key="positive_sample"):
st.session_state.email_body = sample_not_spam_positive
st.session_state.result = ""
st.session_state.result_type = ""
st.rerun()
with col3:
# Button to load negative non-spam sample
if st.button(negative_snippet, key="negative_sample"):
st.session_state.email_body = sample_not_spam_negative
st.session_state.result = ""
st.session_state.result_type = ""
st.rerun()
# Layout for action buttons (Analyze and Clear) in 2 columns
col_analyze, col_clear = st.columns(2)
with col_analyze:
# Button to trigger email analysis (no type="primary" to rely on CSS)
if st.button("Analyze Email", key="analyze"):
if email_body:
with st.spinner("Analyzing email..."): # Show spinner during processing
result_type, result = analyze_email(email_body)
st.session_state.result = result
st.session_state.result_type = result_type
else:
# Error message if no email is provided
st.session_state.result = "Please enter an email body or select a sample to analyze."
st.session_state.result_type = ""
with col_clear:
# Button to reset the app state
if st.button("Clear", key="clear"):
st.session_state.email_body = ""
st.session_state.result = ""
st.session_state.result_type = ""
st.rerun()
# Display the analysis result in styled boxes based on result type
if st.session_state.result:
if st.session_state.result_type == "spam":
st.markdown(f'<div class="spam-result">{st.session_state.result}</div>', unsafe_allow_html=True)
elif st.session_state.result_type == "positive":
st.markdown(f'<div class="positive-result">{st.session_state.result}</div>', unsafe_allow_html=True)
elif st.session_state.result_type == "negative":
st.markdown(f'<div class="negative-result">{st.session_state.result}</div>', unsafe_allow_html=True)
else:
st.write(st.session_state.result) # Display error messages without styling
# Run the app
if __name__ == "__main__":
main() |