File size: 6,088 Bytes
8174974
b3f2d3d
8174974
efa60b3
 
66128ac
efa60b3
8174974
b3f2d3d
8174974
49f0804
 
 
 
 
66128ac
b3f2d3d
efa60b3
8174974
b3f2d3d
8174974
0e52653
66128ac
0e52653
66128ac
 
 
 
b35a08e
 
0e52653
 
b3f2d3d
 
 
 
8174974
49f0804
0ca9296
49f0804
8174974
 
 
0ca9296
 
 
 
 
8174974
 
 
 
 
0ca9296
 
 
66128ac
8174974
 
 
 
b35a08e
49f0804
b35a08e
49f0804
b35a08e
 
 
66128ac
8174974
 
 
 
ef8cc0f
8174974
 
 
 
 
 
 
 
e6fc2f8
 
8174974
e16b3ce
 
8174974
 
 
 
e16b3ce
 
8174974
 
 
e16b3ce
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b3f2d3d
e16b3ce
e6fc2f8
 
e16b3ce
 
 
 
 
 
e6fc2f8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ef8cc0f
8174974
 
 
ef8cc0f
8174974
b3f2d3d
e16b3ce
 
b3f2d3d
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
# Smart Customer Support Assistant (Enhanced UI Version)
# Note: Core analysis logic remains unchanged, now with text generation

import streamlit as st
from transformers import pipeline
import re

# ------------------------------
# Load models (now includes 3rd: text generation)
# ------------------------------
emotion_classifier = pipeline(
    "text-classification",
    model="j-hartmann/emotion-english-distilroberta-base",
    return_all_scores=True
)
intent_classifier = pipeline("zero-shot-classification", model="facebook/bart-large-mnli")
text_generator = pipeline("text2text-generation", model="declare-lab/flan-alpaca-base")

# ------------------------------
# Candidate tasks / prompts
# ------------------------------
candidate_tasks = [
    "change mobile plan",
    "top up balance",
    "report service outage",
    "ask for billing support",
    "reactivate service",
    "cancel subscription",
    "check account status",
    "upgrade device"
]

def generate_response(intent):
    prompt = f"Write a polite and helpful customer service response for this request: '{intent}'"
    output = text_generator(prompt, max_new_tokens=80, do_sample=True)[0]['generated_text']
    return output

urgent_emotions = {"anger", "frustration", "anxiety", "urgency", "afraid", "annoyed"}
moderate_emotions = {"confused", "sad", "tired", "concerned", "sadness"}

# ------------------------------
# Emotion processing
# ------------------------------
def refine_emotion_label(text, model_emotion):
    text_lower = text.lower()
    urgent_keywords = ["fix", "now", "immediately", "urgent", "can't", "need", "asap"]
    exclamations = text.count("!")
    upper_words = sum(1 for word in text.split() if word.isupper())
    signal_score = sum([
        any(word in text_lower for word in urgent_keywords),
        exclamations >= 2,
        upper_words >= 1
    ])
    if model_emotion.lower() in {"joy", "neutral", "sadness"} and signal_score >= 2:
        return "urgency"
    return model_emotion

def get_emotion_label(emotion_result, text):
    sorted_emotions = sorted(emotion_result[0], key=lambda x: x['score'], reverse=True)
    return refine_emotion_label(text, sorted_emotions[0]['label'])

def get_emotion_score(emotion):
    if emotion.lower() in urgent_emotions:
        return 1.0
    elif emotion.lower() in moderate_emotions:
        return 0.6
    else:
        return 0.2

# ------------------------------
# Streamlit UI Logic
# ------------------------------
st.set_page_config(page_title="Smart Customer Support Assistant", layout="centered")
st.title("Smart Customer Support Assistant (for Agents Only)")

# Session state to store chat
if 'chat' not in st.session_state:
    st.session_state.chat = []
if 'system_result' not in st.session_state:
    st.session_state.system_result = None
if 'agent_reply' not in st.session_state:
    st.session_state.agent_reply = ""
if 'support_required' not in st.session_state:
    st.session_state.support_required = ""

# Always show conversation
st.markdown("### Conversation")
for msg in st.session_state.chat:
    with st.chat_message(msg['role']):
        st.markdown(msg['content'])

# Input row with button aligned right
col1, col2 = st.columns([6,1])
with col1:
    user_input = st.text_input("Enter customer message:", key="user_input")
with col2:
    analyze_clicked = st.button("Analyze")

if analyze_clicked and user_input.strip():
    # Run analysis pipeline
    emotion_result = emotion_classifier(user_input)
    emotion_label = get_emotion_label(emotion_result, user_input)
    emotion_score = get_emotion_score(emotion_label)

    intent_result = intent_classifier(user_input, candidate_tasks)
    top_intents = [label for label, score in zip(intent_result['labels'], intent_result['scores']) if score > 0.15][:3]

    content_score = 0.0
    if any(x in user_input.lower() for x in ["out of service", "can't", "urgent", "immediately"]):
        content_score += 0.4
    if any(label in ["top up balance", "reactivate service"] for label in top_intents):
        content_score += 0.4

    final_score = 0.5 * emotion_score + 0.5 * content_score

    st.session_state.chat.append({"role": "user", "content": user_input})

    if final_score < 0.5 and top_intents:
        intent = top_intents[0]
        response = generate_response(intent)
        st.session_state.chat.append({"role": "assistant", "content": response})
        st.session_state.system_result = None
        st.session_state.support_required = "🟒 Automated response handled this request."
    else:
        st.session_state.system_result = {
            "emotion": emotion_label,
            "tone": "Urgent" if emotion_score > 0.8 else "Concerned" if emotion_score > 0.5 else "Calm",
            "intents": top_intents
        }
        st.session_state.support_required = "πŸ”΄ Human support required."

# Show support need status
if st.session_state.support_required:
    st.markdown(f"### {st.session_state.support_required}")

# Always show agent input box
st.subheader("Agent Response Console")
st.session_state.agent_reply = st.text_area("Compose your reply:", value=st.session_state.agent_reply)
if st.button("Send Reply"):
    if st.session_state.agent_reply.strip():
        st.session_state.chat.append({"role": "assistant", "content": st.session_state.agent_reply})
        st.session_state.agent_reply = ""
        st.session_state.system_result = None
        st.session_state.support_required = ""

# If human support needed, show status and suggestions
if st.session_state.system_result is not None:
    st.markdown("#### Customer Status")
    st.markdown(f"- **Emotion:** {st.session_state.system_result['emotion'].capitalize()}")
    st.markdown(f"- **Tone:** {st.session_state.system_result['tone']}")

    st.markdown("#### Detected Customer Needs")
    for intent in st.session_state.system_result['intents']:
        suggestion = generate_response(intent)
        st.markdown(f"**β€’ {intent.capitalize()}**")
        if st.button(suggestion, key=f"btn_{intent}"):
            st.session_state.agent_reply = suggestion