Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -1,8 +1,13 @@
|
|
|
|
|
|
|
|
1 |
import streamlit as st
|
2 |
from transformers import pipeline
|
3 |
import re
|
4 |
|
5 |
-
#
|
|
|
|
|
6 |
emotion_classifier = pipeline(
|
7 |
"text-classification",
|
8 |
model="j-hartmann/emotion-english-distilroberta-base",
|
@@ -10,7 +15,9 @@ emotion_classifier = pipeline(
|
|
10 |
)
|
11 |
intent_classifier = pipeline("zero-shot-classification", model="facebook/bart-large-mnli")
|
12 |
|
13 |
-
#
|
|
|
|
|
14 |
candidate_tasks = [
|
15 |
"change mobile plan",
|
16 |
"top up balance",
|
@@ -22,34 +29,52 @@ candidate_tasks = [
|
|
22 |
"upgrade device"
|
23 |
]
|
24 |
|
25 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
urgent_emotions = {"anger", "frustration", "anxiety", "urgency", "afraid", "annoyed"}
|
27 |
moderate_emotions = {"confused", "sad", "tired", "concerned", "sadness"}
|
28 |
|
29 |
-
#
|
30 |
-
|
31 |
-
|
32 |
-
top_emotion = sorted_emotions[0]['label']
|
33 |
-
return refine_emotion_label(text, top_emotion)
|
34 |
-
|
35 |
def refine_emotion_label(text, model_emotion):
|
36 |
text_lower = text.lower()
|
37 |
urgent_keywords = ["fix", "now", "immediately", "urgent", "can't", "need", "asap"]
|
38 |
exclamations = text.count("!")
|
39 |
upper_words = sum(1 for word in text.split() if word.isupper())
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
signal_score += 1
|
46 |
-
if upper_words >= 1:
|
47 |
-
signal_score += 1
|
48 |
-
|
49 |
if model_emotion.lower() in {"joy", "neutral", "sadness"} and signal_score >= 2:
|
50 |
return "urgency"
|
51 |
return model_emotion
|
52 |
|
|
|
|
|
|
|
|
|
53 |
def get_emotion_score(emotion):
|
54 |
if emotion.lower() in urgent_emotions:
|
55 |
return 1.0
|
@@ -58,95 +83,85 @@ def get_emotion_score(emotion):
|
|
58 |
else:
|
59 |
return 0.2
|
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 |
-
"ask for billing support": "Shall I show your last 3 billing records?",
|
89 |
-
"cancel subscription": "Shall I guide you through cancellation?",
|
90 |
-
"check account status": "Want a summary of your usage and balance?",
|
91 |
-
"upgrade device": "Would you like me to show available upgrade options?"
|
92 |
-
}
|
93 |
-
|
94 |
-
solution = intent_solutions.get(intent.lower(), "Here's how we can assist you with this issue.")
|
95 |
-
closing = intent_closings.get(intent.lower(), "Is there anything else I can help with?")
|
96 |
-
opening = "Thank you for contacting us. I understand your concern."
|
97 |
-
return f"{opening} {solution} {closing}"
|
98 |
-
|
99 |
-
# UI
|
100 |
-
st.set_page_config(page_title="Customer Support Assistant", layout="centered")
|
101 |
-
st.title("📞 Smart Customer Support Assistant (for Agents Only)")
|
102 |
-
|
103 |
-
user_input = st.text_area("Enter customer's message or complaint:", height=150)
|
104 |
-
|
105 |
-
if st.button("Analyze Message"):
|
106 |
-
if user_input.strip() == "":
|
107 |
-
st.warning("Please enter a customer message.")
|
108 |
-
else:
|
109 |
-
with st.spinner("Processing..."):
|
110 |
-
|
111 |
-
# Emotion detection (model + rule)
|
112 |
emotion_result = emotion_classifier(user_input)
|
113 |
emotion_label = get_emotion_label(emotion_result, user_input)
|
114 |
emotion_score = get_emotion_score(emotion_label)
|
115 |
|
116 |
-
# Intent detection
|
117 |
intent_result = intent_classifier(user_input, candidate_tasks)
|
118 |
top_intents = [label for label, score in zip(intent_result['labels'], intent_result['scores']) if score > 0.15][:3]
|
119 |
|
120 |
-
|
121 |
-
|
|
|
|
|
|
|
122 |
|
123 |
-
|
124 |
-
final_score = (0.5 * emotion_score) + (0.5 * content_score)
|
125 |
|
126 |
-
|
|
|
127 |
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
st.markdown("#### 🤖 Auto-Response Sent to User:")
|
134 |
-
st.success(auto_reply)
|
135 |
-
else:
|
136 |
-
st.info("No clear intent detected. A general auto-reply was used.")
|
137 |
else:
|
138 |
-
st.
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Smart Customer Support Assistant (Enhanced UI Version)
|
2 |
+
# Note: Core analysis logic remains unchanged
|
3 |
+
|
4 |
import streamlit as st
|
5 |
from transformers import pipeline
|
6 |
import re
|
7 |
|
8 |
+
# ------------------------------
|
9 |
+
# Load models (same as before)
|
10 |
+
# ------------------------------
|
11 |
emotion_classifier = pipeline(
|
12 |
"text-classification",
|
13 |
model="j-hartmann/emotion-english-distilroberta-base",
|
|
|
15 |
)
|
16 |
intent_classifier = pipeline("zero-shot-classification", model="facebook/bart-large-mnli")
|
17 |
|
18 |
+
# ------------------------------
|
19 |
+
# Candidate tasks / templates
|
20 |
+
# ------------------------------
|
21 |
candidate_tasks = [
|
22 |
"change mobile plan",
|
23 |
"top up balance",
|
|
|
29 |
"upgrade device"
|
30 |
]
|
31 |
|
32 |
+
intent_solutions = {
|
33 |
+
"top up balance": "Your balance is \u00a512. Promo: recharge \u00a5100 get \u00a55 bonus.",
|
34 |
+
"reactivate service": "Service suspended due to unpaid \u00a538. Recharge to restore in 30 mins.",
|
35 |
+
"change mobile plan": "You're on Basic (\u00a568/5GB). Suggest Plus (\u00a598/20GB).",
|
36 |
+
"check account status": "Data: 3.2GB/5GB. Balance: \u00a512. Calls left: 22 mins.",
|
37 |
+
"ask for billing support": "Last bill: \u00a596 (Mar). Includes \u00a516 overage.",
|
38 |
+
"cancel subscription": "Contract ends: 2025-06-30. No penalty after this date.",
|
39 |
+
"upgrade device": "Eligible for upgrade. New iPhone plan: \u00a5399/month.",
|
40 |
+
"report service outage": "Signal issues detected (ZIP: XXX). Engineers notified."
|
41 |
+
}
|
42 |
+
|
43 |
+
intent_closings = {
|
44 |
+
"top up balance": "Proceed with recharge now?",
|
45 |
+
"reactivate service": "Shall I help restart your service?",
|
46 |
+
"report service outage": "Shall I file a service report?",
|
47 |
+
"change mobile plan": "Switch to a better plan?",
|
48 |
+
"ask for billing support": "Show recent billing records?",
|
49 |
+
"cancel subscription": "Guide you through cancellation?",
|
50 |
+
"check account status": "Show usage and balance?",
|
51 |
+
"upgrade device": "See available upgrades?"
|
52 |
+
}
|
53 |
+
|
54 |
urgent_emotions = {"anger", "frustration", "anxiety", "urgency", "afraid", "annoyed"}
|
55 |
moderate_emotions = {"confused", "sad", "tired", "concerned", "sadness"}
|
56 |
|
57 |
+
# ------------------------------
|
58 |
+
# Emotion processing
|
59 |
+
# ------------------------------
|
|
|
|
|
|
|
60 |
def refine_emotion_label(text, model_emotion):
|
61 |
text_lower = text.lower()
|
62 |
urgent_keywords = ["fix", "now", "immediately", "urgent", "can't", "need", "asap"]
|
63 |
exclamations = text.count("!")
|
64 |
upper_words = sum(1 for word in text.split() if word.isupper())
|
65 |
+
signal_score = sum([
|
66 |
+
any(word in text_lower for word in urgent_keywords),
|
67 |
+
exclamations >= 2,
|
68 |
+
upper_words >= 1
|
69 |
+
])
|
|
|
|
|
|
|
|
|
70 |
if model_emotion.lower() in {"joy", "neutral", "sadness"} and signal_score >= 2:
|
71 |
return "urgency"
|
72 |
return model_emotion
|
73 |
|
74 |
+
def get_emotion_label(emotion_result, text):
|
75 |
+
sorted_emotions = sorted(emotion_result[0], key=lambda x: x['score'], reverse=True)
|
76 |
+
return refine_emotion_label(text, sorted_emotions[0]['label'])
|
77 |
+
|
78 |
def get_emotion_score(emotion):
|
79 |
if emotion.lower() in urgent_emotions:
|
80 |
return 1.0
|
|
|
83 |
else:
|
84 |
return 0.2
|
85 |
|
86 |
+
# ------------------------------
|
87 |
+
# Streamlit UI Logic
|
88 |
+
# ------------------------------
|
89 |
+
st.set_page_config(page_title="Smart Customer Support Assistant", layout="centered")
|
90 |
+
st.title("\ud83d\udcde Smart Customer Support Assistant (for Agents Only)")
|
91 |
+
|
92 |
+
# Session state to store chat
|
93 |
+
if 'chat' not in st.session_state:
|
94 |
+
st.session_state.chat = []
|
95 |
+
if 'system_result' not in st.session_state:
|
96 |
+
st.session_state.system_result = None
|
97 |
+
if 'agent_reply' not in st.session_state:
|
98 |
+
st.session_state.agent_reply = ""
|
99 |
+
|
100 |
+
# Display chat history
|
101 |
+
for msg in st.session_state.chat:
|
102 |
+
with st.chat_message(msg['role']):
|
103 |
+
st.markdown(msg['content'])
|
104 |
+
|
105 |
+
# Customer input + Analyze button
|
106 |
+
col1, col2 = st.columns([5,1])
|
107 |
+
with col1:
|
108 |
+
user_input = st.text_input("Enter customer message:", key="user_input")
|
109 |
+
with col2:
|
110 |
+
if st.button("Analyze"):
|
111 |
+
if user_input.strip():
|
112 |
+
# Run analysis pipeline
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
113 |
emotion_result = emotion_classifier(user_input)
|
114 |
emotion_label = get_emotion_label(emotion_result, user_input)
|
115 |
emotion_score = get_emotion_score(emotion_label)
|
116 |
|
|
|
117 |
intent_result = intent_classifier(user_input, candidate_tasks)
|
118 |
top_intents = [label for label, score in zip(intent_result['labels'], intent_result['scores']) if score > 0.15][:3]
|
119 |
|
120 |
+
content_score = 0.0
|
121 |
+
if any(x in user_input.lower() for x in ["out of service", "can't", "urgent", "immediately"]):
|
122 |
+
content_score += 0.4
|
123 |
+
if any(label in ["top up balance", "reactivate service"] for label in top_intents):
|
124 |
+
content_score += 0.4
|
125 |
|
126 |
+
final_score = 0.5 * emotion_score + 0.5 * content_score
|
|
|
127 |
|
128 |
+
# Store user message
|
129 |
+
st.session_state.chat.append({"role": "user", "content": user_input})
|
130 |
|
131 |
+
# Auto response or escalate to agent
|
132 |
+
if final_score < 0.5 and top_intents:
|
133 |
+
intent = top_intents[0]
|
134 |
+
response = f"Thank you for contacting us. I understand your concern. {intent_solutions[intent]} {intent_closings[intent]}"
|
135 |
+
st.session_state.chat.append({"role": "assistant", "content": response})
|
|
|
|
|
|
|
|
|
136 |
else:
|
137 |
+
st.session_state.system_result = {
|
138 |
+
"emotion": emotion_label,
|
139 |
+
"tone": "Urgent" if emotion_score > 0.8 else "Concerned" if emotion_score > 0.5 else "Calm",
|
140 |
+
"intents": top_intents
|
141 |
+
}
|
142 |
+
|
143 |
+
# If human support needed
|
144 |
+
if st.session_state.system_result:
|
145 |
+
st.markdown("---")
|
146 |
+
st.subheader("\ud83d\udc69\u200d\ud83d\udcbb Agent Response Panel")
|
147 |
+
|
148 |
+
# Agent editable response
|
149 |
+
st.session_state.agent_reply = st.text_area("Compose your reply:", value=st.session_state.agent_reply)
|
150 |
+
if st.button("Send Reply"):
|
151 |
+
if st.session_state.agent_reply.strip():
|
152 |
+
st.session_state.chat.append({"role": "assistant", "content": st.session_state.agent_reply})
|
153 |
+
st.session_state.agent_reply = ""
|
154 |
+
st.session_state.system_result = None
|
155 |
+
|
156 |
+
# Context info
|
157 |
+
st.markdown("#### \ud83d\udc64 Customer Status")
|
158 |
+
st.markdown(f"- **Emotion:** {st.session_state.system_result['emotion'].capitalize()}")
|
159 |
+
st.markdown(f"- **Tone:** {st.session_state.system_result['tone']}")
|
160 |
+
|
161 |
+
# Suggested replies
|
162 |
+
st.markdown("#### \ud83e\uddf0 Detected Customer Needs")
|
163 |
+
for intent in st.session_state.system_result['intents']:
|
164 |
+
st.markdown(f"**• {intent.capitalize()}**")
|
165 |
+
suggestion = f"Thank you for contacting us. I understand your concern. {intent_solutions[intent]} {intent_closings[intent]}"
|
166 |
+
if st.button(f"Use suggestion for '{intent}'", key=intent):
|
167 |
+
st.session_state.agent_reply = suggestion
|