File size: 6,972 Bytes
efa60b3
 
 
80c829c
49f0804
 
 
 
 
66128ac
b3f2d3d
efa60b3
80c829c
0e52653
80c829c
 
 
0e52653
 
80c829c
49f0804
0ca9296
49f0804
80c829c
0ca9296
 
 
 
80c829c
8174974
 
 
 
 
0ca9296
 
 
66128ac
80c829c
 
8174974
 
b35a08e
49f0804
b35a08e
49f0804
b35a08e
 
 
66128ac
8333387
07994df
 
 
 
 
 
 
 
 
 
 
 
 
8333387
 
07994df
80c829c
29a8952
 
8333387
29a8952
 
8333387
 
 
80c829c
29a8952
 
 
80c829c
 
29a8952
8333387
29a8952
ef8cc0f
8174974
80c829c
e16b3ce
29a8952
e3ac22d
 
8174974
 
80c829c
8333387
8174974
8333387
8174974
80c829c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29a8952
 
e6fc2f8
80c829c
e6fc2f8
8333387
e6fc2f8
29a8952
e3ac22d
29a8952
 
 
8333387
29a8952
80c829c
29a8952
ef8cc0f
29a8952
 
ef8cc0f
80c829c
e3ac22d
e16b3ce
d40453d
e3ac22d
80c829c
e3ac22d
 
 
 
 
223059a
e3ac22d
8333387
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
import streamlit as st
from transformers import pipeline

# Load Models
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")

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

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

# Utilities
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 w in text.split() if w.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(result, text):
    sorted_emotions = sorted(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

def generate_response(intent, human=True):
    if human:
        prompt = (
            f"You are a telecom customer service agent. For the customer intent '{intent}', generate a professional 3-part response:\n"
            "1. Greeting (e.g., Thank you for contacting us...)\n"
            "2. Current plan summary (e.g., You're currently on Plan X at Β₯X/month. We suggest Plan Y with XXGB for Β₯Y/month.)\n"
            "3. Close with a question (e.g., Would you like to switch?)"
        )
    else:
        prompt = (
            f"As a telecom assistant, generate a full 3-part structured response for customer intent: '{intent}'.\n"
            "Include greeting, summary of their current plan and a better offer (fictional), and end with a follow-up question."
        )
    result = text_generator(prompt, max_new_tokens=120, do_sample=False)
    return result[0]['generated_text'].strip()


# App UI Setup
st.set_page_config(page_title="Smart Customer Support Assistant", layout="wide")
st.sidebar.title("πŸ“ Customer Selector")

if "customers" not in st.session_state:
    st.session_state.customers = {"Customer A": [], "Customer B": [], "Customer C": []}
if "chat_sessions" not in st.session_state:
    st.session_state.chat_sessions = {}

selected_customer = st.sidebar.selectbox("Choose a customer:", list(st.session_state.customers.keys()))

if selected_customer not in st.session_state.chat_sessions:
    st.session_state.chat_sessions[selected_customer] = {
        "chat": [], "system_result": None,
        "agent_reply": "", "support_required": "", "user_input": ""
    }

session = st.session_state.chat_sessions[selected_customer]
st.title("Smart Customer Support Assistant (for Agents Only)")

# Conversation Window
st.markdown("### Conversation")
for msg in session["chat"]:
    avatar = "πŸ‘€" if msg['role'] == 'user' else ("πŸ€–" if msg.get("auto") else "πŸ‘¨β€πŸ’Ό")
    with st.chat_message(msg['role'], avatar=avatar):
        st.markdown(msg['content'])

# Input & Analysis
col1, col2 = st.columns([6, 1])
with col1:
    user_input = st.text_input("Enter customer message:", key="customer_input")
with col2:
    if st.button("Analyze"):
        if user_input.strip():
            session["chat"].append({"role": "user", "content": user_input})
            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

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

# Support Tag
if session["support_required"]:
    st.markdown(f"### {session['support_required']}")

# Agent Reply Console
st.subheader("Agent Response Console")
session["agent_reply"] = st.text_area("Compose your reply:", value=session["agent_reply"], key="agent_reply_box")
if st.button("Send Reply"):
    if session["agent_reply"].strip():
        session["chat"].append({"role": "assistant", "content": session["agent_reply"], "auto": False})
        session["agent_reply"] = ""
        session["system_result"] = None
        session["support_required"] = ""
        st.experimental_rerun()

# Human Needed View
if session["system_result"] is not None:
    st.markdown("#### Customer Status")
    st.markdown(f"- **Emotion:** {session['system_result']['emotion'].capitalize()}")
    st.markdown(f"- **Tone:** {session['system_result']['tone']}")
    st.markdown("#### Detected Customer Needs")
    for intent in session["system_result"]["intents"]:
        suggestion = generate_response(intent, human=True)
        st.markdown(f"**β€’ {intent.capitalize()}**")
        st.code(suggestion)

# End Button
if st.button("End Conversation"):
    session["chat"] = []
    session["system_result"] = None
    session["agent_reply"] = ""
    session["support_required"] = ""
    session["user_input"] = ""
    st.success("Conversation ended and cleared.")
    st.rerun()