ISOM5240GP4 commited on
Commit
0b21d86
·
verified ·
1 Parent(s): 7817e88

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +135 -127
app.py CHANGED
@@ -3,57 +3,70 @@ from transformers import pipeline, AutoModelForSequenceClassification, AutoToken
3
  import torch
4
  import numpy as np
5
 
6
- # Function to analyze email for spam and sentiment
7
- def analyze_email(email_body):
8
- # Load pre-trained models: spam detection and sentiment analysis
9
- spam_pipeline = pipeline("text-classification", model="cybersectony/phishing-email-detection-distilbert_v2.4.1")
10
- sentiment_model = AutoModelForSequenceClassification.from_pretrained("ISOM5240GP4/email_sentiment", num_labels=2)
 
 
 
11
  tokenizer = AutoTokenizer.from_pretrained("distilbert-base-uncased")
 
12
 
13
- # Step 1: Check if the email is spam using the spam detection model
14
- spam_result = spam_pipeline(email_body)
15
- spam_label = spam_result[0]["label"] # LABEL_1 indicates spam
16
- spam_confidence = spam_result[0]["score"]
17
-
18
- if spam_label == "LABEL_1":
19
- # If spam, return type "spam" and a message indicating no follow-up
20
- return "spam", f"This is a spam email (Confidence: {spam_confidence:.2f}). No follow-up needed."
21
- else:
22
- # Step 2: For non-spam emails, analyze sentiment (positive/negative)
23
- inputs = tokenizer(email_body, padding=True, truncation=True, return_tensors='pt') # Tokenize input
24
- outputs = sentiment_model(**inputs) # Get model predictions
25
- predictions = torch.nn.functional.softmax(outputs.logits, dim=-1) # Apply softmax for probabilities
26
- predictions = predictions.cpu().detach().numpy() # Convert to numpy array
27
- sentiment_index = np.argmax(predictions) # Get the predicted sentiment (0 = negative, 1 = positive)
28
- sentiment_confidence = predictions[0][sentiment_index]
29
- sentiment = "Positive" if sentiment_index == 1 else "Negative"
30
 
31
- if sentiment == "Positive":
32
- # If positive sentiment, no follow-up needed
33
- return "positive", (f"This email is not spam (Confidence: {spam_confidence:.2f}).\n"
34
- f"Sentiment: {sentiment} (Confidence: {sentiment_confidence:.2f}). No follow-up needed.")
 
 
 
 
 
 
 
 
 
 
35
  else:
36
- # If negative sentiment, mark as needing follow-up with bolded text
37
- return "negative", (f"This email is not spam (Confidence: {spam_confidence:.2f}).\n"
38
- f"Sentiment: {sentiment} (Confidence: {sentiment_confidence:.2f}).\n"
39
- "<b>Need to Follow-Up</b>: This email is not spam and has negative sentiment.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
 
41
  # Main application function
42
  def main():
43
- # Set the app title to the project name
44
  st.title("EmailSentry")
45
- # Display the project objective
46
  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.")
47
-
48
- # Initialize session state to store email input and analysis results
49
  if "email_body" not in st.session_state:
50
- st.session_state.email_body = "" # Holds the email text
51
  if "result" not in st.session_state:
52
- st.session_state.result = "" # Stores the analysis result text
53
  if "result_type" not in st.session_state:
54
- st.session_state.result_type = "" # Tracks result type (spam, positive, negative)
55
-
56
- # Add collapsible instructions for user guidance
57
  with st.expander("How to Use", expanded=False):
58
  st.write("""
59
  - Type or paste an email into the text box.
@@ -61,11 +74,11 @@ def main():
61
  - Press 'Analyze Email' to check if it’s spam and analyze its sentiment.
62
  - Use 'Clear' to reset the input and result.
63
  """)
64
-
65
- # Text area where users input or view the email body
66
  email_body = st.text_area("Email Body", value=st.session_state.email_body, height=200, key="email_input")
67
-
68
- # Define sample emails and their snippets for example buttons
69
  sample_spam = """
70
  Subject: Urgent: Verify Your Account Now!
71
  Dear Customer,
@@ -76,7 +89,7 @@ Best regards,
76
  The Security Team
77
  """
78
  spam_snippet = "Subject: Urgent: Verify Your Account Now! Dear Customer, We have detected unusual activity..."
79
-
80
  sample_not_spam_positive = """
81
  Subject: Great Experience with HKTV mall
82
  Dear Sir,
@@ -85,7 +98,7 @@ Best regards,
85
  Emily
86
  """
87
  positive_snippet = "Subject: Great Experience with HKTV mall Dear Sir, I just received my order and I’m really..."
88
-
89
  sample_not_spam_negative = """
90
  Subject: Issue with Recent Delivery
91
  Dear Support,
@@ -94,13 +107,69 @@ Thanks,
94
  Sarah
95
  """
96
  negative_snippet = "Subject: Issue with Recent Delivery Dear Support, I received my package today, but..."
97
-
98
- # Custom CSS for styling buttons and result boxes with higher specificity
99
- # Replace your existing st.markdown CSS block with this
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  st.markdown("""
101
  <style>
102
- /* Ensure high specificity for Analyze Email button (orange) */
103
- div[data-testid="stButton"] > button[key="analyze"] {
104
  background-color: #FF5733 !important; /* Orange */
105
  color: white !important;
106
  font-size: 18px !important;
@@ -113,12 +182,12 @@ Sarah
113
  text-align: center !important;
114
  margin: 0 !important;
115
  }
116
- div[data-testid="stButton"] > button[key="analyze"]:hover {
117
- background-color: #E74C3C !important; /* Darker orange on hover */
118
  }
119
-
120
- /* Ensure high specificity for Clear button (blue) */
121
- div[data-testid="stButton"] > button[key="clear"] {
122
  background-color: #007BFF !important; /* Blue */
123
  color: white !important;
124
  font-size: 18px !important;
@@ -131,37 +200,37 @@ Sarah
131
  text-align: center !important;
132
  margin: 0 !important;
133
  }
134
- div[data-testid="stButton"] > button[key="clear"]:hover {
135
- background-color: #0056b3 !important; /* Darker blue on hover */
136
  }
137
-
138
- /* Style for sample buttons (light gray) */
139
- div[data-testid="stButton"] > button[kind="secondary"]:not([key="clear"]):not([key="analyze"]) {
140
  font-size: 12px !important;
141
  padding: 5px 10px !important;
142
- background-color: #f0f0f0 !important;
143
  color: #333333 !important;
144
  border: 1px solid #cccccc !important;
145
  border-radius: 3px !important;
146
  }
147
-
148
- /* Result boxes (unchanged) */
149
  .spam-result {
150
- background-color: #ff3333 !important; /* Red for no follow-up (spam) */
151
  color: white !important;
152
  padding: 10px !important;
153
  border-radius: 5px !important;
154
  border: 1px solid #cc0000 !important;
155
  }
156
  .positive-result {
157
- background-color: #ff3333 !important; /* Red for no follow-up (positive) */
158
  color: white !important;
159
  padding: 10px !important;
160
  border-radius: 5px !important;
161
  border: 1px solid #cc0000 !important;
162
  }
163
  .negative-result {
164
- background-color: #006633 !important; /* Dark green for follow-up needed */
165
  color: white !important;
166
  padding: 10px !important;
167
  border-radius: 5px !important;
@@ -170,66 +239,5 @@ Sarah
170
  </style>
171
  """, unsafe_allow_html=True)
172
 
173
- # Subheading to label the sample email buttons
174
- st.subheader("Examples")
175
-
176
- # Layout for sample buttons in 3 columns
177
- col1, col2, col3 = st.columns(3)
178
- with col1:
179
- # Button to load spam sample
180
- if st.button(spam_snippet, key="spam_sample"):
181
- st.session_state.email_body = sample_spam
182
- st.session_state.result = ""
183
- st.session_state.result_type = ""
184
- st.rerun()
185
- with col2:
186
- # Button to load positive non-spam sample
187
- if st.button(positive_snippet, key="positive_sample"):
188
- st.session_state.email_body = sample_not_spam_positive
189
- st.session_state.result = ""
190
- st.session_state.result_type = ""
191
- st.rerun()
192
- with col3:
193
- # Button to load negative non-spam sample
194
- if st.button(negative_snippet, key="negative_sample"):
195
- st.session_state.email_body = sample_not_spam_negative
196
- st.session_state.result = ""
197
- st.session_state.result_type = ""
198
- st.rerun()
199
-
200
- # Layout for action buttons (Analyze and Clear) in 2 columns
201
- col_analyze, col_clear = st.columns(2)
202
- with col_analyze:
203
- # Button to trigger email analysis (no type="primary" to rely on CSS)
204
- if st.button("Analyze Email", key="analyze"):
205
- if email_body:
206
- with st.spinner("Analyzing email..."): # Show spinner during processing
207
- result_type, result = analyze_email(email_body)
208
- st.session_state.result = result
209
- st.session_state.result_type = result_type
210
- else:
211
- # Error message if no email is provided
212
- st.session_state.result = "Please enter an email body or select a sample to analyze."
213
- st.session_state.result_type = ""
214
- with col_clear:
215
- # Button to reset the app state
216
- if st.button("Clear", key="clear"):
217
- st.session_state.email_body = ""
218
- st.session_state.result = ""
219
- st.session_state.result_type = ""
220
- st.rerun()
221
-
222
- # Display the analysis result in styled boxes based on result type
223
- if st.session_state.result:
224
- if st.session_state.result_type == "spam":
225
- st.markdown(f'<div class="spam-result">{st.session_state.result}</div>', unsafe_allow_html=True)
226
- elif st.session_state.result_type == "positive":
227
- st.markdown(f'<div class="positive-result">{st.session_state.result}</div>', unsafe_allow_html=True)
228
- elif st.session_state.result_type == "negative":
229
- st.markdown(f'<div class="negative-result">{st.session_state.result}</div>', unsafe_allow_html=True)
230
- else:
231
- st.write(st.session_state.result) # Display error messages without styling
232
-
233
- # Run the app
234
  if __name__ == "__main__":
235
  main()
 
3
  import torch
4
  import numpy as np
5
 
6
+ # Load models with caching to improve performance
7
+ @st.cache_resource
8
+ def load_spam_pipeline():
9
+ return pipeline("text-classification", model="cybersectony/phishing-email-detection-distilbert_v2.4.1")
10
+
11
+ @st.cache_resource
12
+ def load_sentiment_model():
13
+ model = AutoModelForSequenceClassification.from_pretrained("ISOM5240GP4/email_sentiment", num_labels=2)
14
  tokenizer = AutoTokenizer.from_pretrained("distilbert-base-uncased")
15
+ return model, tokenizer
16
 
17
+ # Initialize models
18
+ spam_pipeline = load_spam_pipeline()
19
+ sentiment_model, tokenizer = load_sentiment_model()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
 
21
+ # Function to analyze email
22
+ def analyze_email(email_body):
23
+ """Analyzes an email for spam and sentiment, returning result type and message."""
24
+ if not email_body.strip():
25
+ return "error", "Email body is empty. Please provide an email to analyze."
26
+
27
+ try:
28
+ # Step 1: Check if the email is spam
29
+ spam_result = spam_pipeline(email_body)
30
+ spam_label = spam_result[0]["label"] # LABEL_1 indicates spam
31
+ spam_confidence = spam_result[0]["score"]
32
+
33
+ if spam_label == "LABEL_1":
34
+ return "spam", f"This is a spam email (Confidence: {spam_confidence:.2f}). No follow-up needed."
35
  else:
36
+ # Step 2: Analyze sentiment for non-spam emails
37
+ inputs = tokenizer(email_body, padding=True, truncation=True, return_tensors='pt')
38
+ outputs = sentiment_model(**inputs)
39
+ predictions = torch.nn.functional.softmax(outputs.logits, dim=-1)
40
+ predictions = predictions.cpu().detach().numpy()
41
+ sentiment_index = np.argmax(predictions)
42
+ sentiment_confidence = predictions[0][sentiment_index]
43
+ sentiment = "Positive" if sentiment_index == 1 else "Negative"
44
+
45
+ if sentiment == "Positive":
46
+ return "positive", (f"This email is not spam (Confidence: {spam_confidence:.2f}).\n"
47
+ f"Sentiment: {sentiment} (Confidence: {sentiment_confidence:.2f}). No follow-up needed.")
48
+ else:
49
+ return "negative", (f"This email is not spam (Confidence: {spam_confidence:.2f}).\n"
50
+ f"Sentiment: {sentiment} (Confidence: {sentiment_confidence:.2f}).\n"
51
+ "<b>Need to Follow-Up</b>: This email is not spam and has negative sentiment.")
52
+ except Exception as e:
53
+ return "error", f"An error occurred during analysis: {str(e)}"
54
 
55
  # Main application function
56
  def main():
57
+ # Set title and objective
58
  st.title("EmailSentry")
 
59
  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.")
60
+
61
+ # Initialize session state variables
62
  if "email_body" not in st.session_state:
63
+ st.session_state.email_body = ""
64
  if "result" not in st.session_state:
65
+ st.session_state.result = ""
66
  if "result_type" not in st.session_state:
67
+ st.session_state.result_type = ""
68
+
69
+ # Instructions section
70
  with st.expander("How to Use", expanded=False):
71
  st.write("""
72
  - Type or paste an email into the text box.
 
74
  - Press 'Analyze Email' to check if it’s spam and analyze its sentiment.
75
  - Use 'Clear' to reset the input and result.
76
  """)
77
+
78
+ # Text area for email input
79
  email_body = st.text_area("Email Body", value=st.session_state.email_body, height=200, key="email_input")
80
+
81
+ # Define sample emails
82
  sample_spam = """
83
  Subject: Urgent: Verify Your Account Now!
84
  Dear Customer,
 
89
  The Security Team
90
  """
91
  spam_snippet = "Subject: Urgent: Verify Your Account Now! Dear Customer, We have detected unusual activity..."
92
+
93
  sample_not_spam_positive = """
94
  Subject: Great Experience with HKTV mall
95
  Dear Sir,
 
98
  Emily
99
  """
100
  positive_snippet = "Subject: Great Experience with HKTV mall Dear Sir, I just received my order and I’m really..."
101
+
102
  sample_not_spam_negative = """
103
  Subject: Issue with Recent Delivery
104
  Dear Support,
 
107
  Sarah
108
  """
109
  negative_snippet = "Subject: Issue with Recent Delivery Dear Support, I received my package today, but..."
110
+
111
+ # Display sample buttons
112
+ st.subheader("Examples")
113
+ col1, col2, col3 = st.columns(3)
114
+ with col1:
115
+ if st.button(spam_snippet, key="spam_sample"):
116
+ st.session_state.email_body = sample_spam
117
+ st.session_state.result = ""
118
+ st.session_state.result_type = ""
119
+ st.rerun()
120
+ with col2:
121
+ if st.button(positive_snippet, key="positive_sample"):
122
+ st.session_state.email_body = sample_not_spam_positive
123
+ st.session_state.result = ""
124
+ st.session_state.result_type = ""
125
+ st.rerun()
126
+ with col3:
127
+ if st.button(negative_snippet, key="negative_sample"):
128
+ st.session_state.email_body = sample_not_spam_negative
129
+ st.session_state.result = ""
130
+ st.session_state.result_type = ""
131
+ st.rerun()
132
+
133
+ # Action buttons with custom styling wrappers
134
+ col_analyze, col_clear = st.columns(2)
135
+ with col_analyze:
136
+ st.markdown('<div id="analyze-button">', unsafe_allow_html=True)
137
+ if st.button("Analyze Email", key="analyze"):
138
+ if email_body:
139
+ with st.spinner("Analyzing email..."):
140
+ result_type, result = analyze_email(email_body)
141
+ st.session_state.result = result
142
+ st.session_state.result_type = result_type
143
+ else:
144
+ st.session_state.result = "Please enter an email body or select a sample to analyze."
145
+ st.session_state.result_type = ""
146
+ st.markdown('</div>', unsafe_allow_html=True)
147
+
148
+ with col_clear:
149
+ st.markdown('<div id="clear-button">', unsafe_allow_html=True)
150
+ if st.button("Clear", key="clear"):
151
+ st.session_state.email_body = ""
152
+ st.session_state.result = ""
153
+ st.session_state.result_type = ""
154
+ st.rerun()
155
+ st.markdown('</div>', unsafe_allow_html=True)
156
+
157
+ # Display analysis result
158
+ if st.session_state.result:
159
+ if st.session_state.result_type == "spam":
160
+ st.markdown(f'<div class="spam-result">{st.session_state.result}</div>', unsafe_allow_html=True)
161
+ elif st.session_state.result_type == "positive":
162
+ st.markdown(f'<div class="positive-result">{st.session_state.result}</div>', unsafe_allow_html=True)
163
+ elif st.session_state.result_type == "negative":
164
+ st.markdown(f'<div class="negative-result">{st.session_state.result}</div>', unsafe_allow_html=True)
165
+ else:
166
+ st.write(st.session_state.result)
167
+
168
+ # Inject custom CSS for styling
169
  st.markdown("""
170
  <style>
171
+ /* Style for Analyze Email button */
172
+ #analyze-button button {
173
  background-color: #FF5733 !important; /* Orange */
174
  color: white !important;
175
  font-size: 18px !important;
 
182
  text-align: center !important;
183
  margin: 0 !important;
184
  }
185
+ #analyze-button button:hover {
186
+ background-color: #E74C3C !important; /* Darker orange */
187
  }
188
+
189
+ /* Style for Clear button */
190
+ #clear-button button {
191
  background-color: #007BFF !important; /* Blue */
192
  color: white !important;
193
  font-size: 18px !important;
 
200
  text-align: center !important;
201
  margin: 0 !important;
202
  }
203
+ #clear-button button:hover {
204
+ background-color: #0056b3 !important; /* Darker blue */
205
  }
206
+
207
+ /* Style for sample buttons */
208
+ div[data-testid="stButton"] button:not([key="analyze"]):not([key="clear"]) {
209
  font-size: 12px !important;
210
  padding: 5px 10px !important;
211
+ background-color: #f0f0f0 !important; /* Light gray */
212
  color: #333333 !important;
213
  border: 1px solid #cccccc !important;
214
  border-radius: 3px !important;
215
  }
216
+
217
+ /* Result boxes */
218
  .spam-result {
219
+ background-color: #ff3333 !important; /* Red */
220
  color: white !important;
221
  padding: 10px !important;
222
  border-radius: 5px !important;
223
  border: 1px solid #cc0000 !important;
224
  }
225
  .positive-result {
226
+ background-color: #ff3333 !important; /* Red */
227
  color: white !important;
228
  padding: 10px !important;
229
  border-radius: 5px !important;
230
  border: 1px solid #cc0000 !important;
231
  }
232
  .negative-result {
233
+ background-color: #006633 !important; /* Dark green */
234
  color: white !important;
235
  padding: 10px !important;
236
  border-radius: 5px !important;
 
239
  </style>
240
  """, unsafe_allow_html=True)
241
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
  if __name__ == "__main__":
243
  main()