mclvntr commited on
Commit
54d270e
·
1 Parent(s): 17bca40

Demo Upload - First Commit

Browse files
Files changed (9) hide show
  1. README.md +5 -1
  2. app.py +369 -4
  3. icons/CT.svg +46 -0
  4. icons/GP.svg +41 -0
  5. icons/GS.svg +39 -0
  6. icons/M.svg +58 -0
  7. icons/P.svg +41 -0
  8. requierements.txt +2 -0
  9. styles.css +199 -0
README.md CHANGED
@@ -7,7 +7,11 @@ sdk: gradio
7
  sdk_version: 4.38.1
8
  app_file: app.py
9
  pinned: false
10
- license: cc-by-nc-sa-4.0
11
  ---
12
 
 
 
 
 
13
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
7
  sdk_version: 4.38.1
8
  app_file: app.py
9
  pinned: false
10
+ license: other
11
  ---
12
 
13
+ All rights reserved to Traceflow Ltd.
14
+ Visit https://blankstate.ai
15
+ Contact us contact@blankstate.ai
16
+
17
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app.py CHANGED
@@ -1,7 +1,372 @@
1
  import gradio as gr
 
 
 
 
 
 
 
2
 
3
- def greet(name):
4
- return "Hello " + name + "!!"
5
 
6
- demo = gr.Interface(fn=greet, inputs="text", outputs="text")
7
- demo.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import gradio as gr
2
+ import time
3
+ import random
4
+ import os
5
+ import base64
6
+ import json
7
+ import requests
8
+ import redis
9
 
10
+ #from huggingface_hub import login
 
11
 
12
+ # Global variables
13
+ picked_blueprint_js = None
14
+ protocol_scores = {}
15
+ protocol_markdown = None
16
+ DEFAULT_BLUEPRINT_INDEX = 0
17
+ DEFAULT_CONVERSATION_TYPE = "Banking"
18
+
19
+ HF_TOKEN = os.environ.get('PRIVATE_TOKEN')
20
+
21
+ COGN_API_URL = os.environ.get('BLANK_API_ENDPOINT')
22
+
23
+ headers = {
24
+ "Authorization": f"Bearer {HF_TOKEN}",
25
+ "Content-Type": "application/json",
26
+ }
27
+
28
+ R_PWD = os.environ['REDIS_CRED']
29
+ R_HOST = os.environ['REDIS_HOST']
30
+ r = redis.Redis(
31
+ host=R_HOST,
32
+ port=13508,
33
+ password=R_PWD)
34
+
35
+ # Predefined conversation examples
36
+ conversations = {
37
+ "Banking": [
38
+ ("Banker", "Hello, welcome to our bank. How may I assist you today?"),
39
+ ("Client", "Good afternoon, I am looking to apply for a personal loan to cover some unexpected expenses."),
40
+ ("Banker", "Certainly, can you please provide us with some details about your income, expenses, and the amount you are looking to borrow?"),
41
+ ("Client", "Yes, my monthly income is around $4,500, and my expenses are roughly $3,500. I'm looking to borrow $5,000 for a period of 2 years."),
42
+ ("Banker", "Based on your income and expenses, we can offer you a loan with an interest rate of 5.5% per annum, with monthly repayments of $272. Would that be acceptable to you?"),
43
+ ("Client", "Yes, that's reasonable. Can you please provide me with the necessary paperwork to complete the application process?"),
44
+ ("Banker", "Absolutely, I will have a loan application form for you to fill out, as well as some documents to verify your income and identity. Once we have all the required information, we can process your loan application and get back to you as soon as possible."),
45
+ ("Client", "Thank you very much, I appreciate your help. I look forward to doing business with your bank."),
46
+ ("Banker", "It's been my pleasure, and we're confident that we can provide you with the financial solutions you need. Don't hesitate to reach out if you have any further questions or concerns."),
47
+ ("Client", "Thank you, I'll be in touch. Goodbye for now."),
48
+ ("Banker", "Goodbye, have a great day!")
49
+ ],
50
+ "Unhappy Customer": [
51
+ ("Customer Service", "Thank you for contacting customer service. I understand you're having an issue. Could you please explain what's wrong?"),
52
+ ("Customer", "I'm very unhappy with the service I received. My order arrived damaged and the support I received was not helpful."),
53
+ ("Customer Service", "I'm really sorry to hear that. Could you provide me with your order number so I can look into this for you?"),
54
+ ("Customer", "Sure, it's 12345."),
55
+ ("Customer Service", "Thank you. I'll check the details and see what we can do to resolve this issue for you."),
56
+ ("Customer", "Thank you."),
57
+ ("Customer Service", "I've checked your order and see the issue. We'll send you a replacement immediately and offer a discount on your next purchase."),
58
+ ("Customer", "I appreciate that. Thank you for your help."),
59
+ ("Customer Service", "You're welcome. Is there anything else I can assist you with?"),
60
+ ("Customer", "No, that's all. Thank you."),
61
+ ("Customer Service", "Have a great day!")
62
+ ],
63
+ "Internal": [
64
+ ("Employee 1", "Hey colleague, do you have a minute to discuss the new project?"),
65
+ ("Employee 2", "Sure, what's up?"),
66
+ ("Employee 1", "I think we need to re-evaluate our timeline. The client has requested some changes that will impact our deadlines."),
67
+ ("Employee 2", "I agree. Let's set up a meeting with the team to discuss the adjustments and update our schedule."),
68
+ ("Employee 1", "Sounds good. I'll send out a meeting invite for tomorrow."),
69
+ ("Employee 2", "Great, thanks for coordinating this."),
70
+ ("Employee 1", "No problem. See you at the meeting."),
71
+ ("Employee 2", "See you!")
72
+ ]
73
+ }
74
+
75
+ # Load blueprints and protocols
76
+ def load_blueprints_and_protocols():
77
+ try:
78
+ data = r.json().get("bp_patterns_seeker")
79
+ except redis.exceptions.ResponseError as e:
80
+ return ("Error:", e)
81
+
82
+
83
+
84
+ blueprints = [blueprint["name"] for blueprint in data["blueprints"]]
85
+ protocols = {blueprint["name"]: {ptype: [] for ptype in ["CT", "GS", "GP", "P", "M"]} for blueprint in data["blueprints"]}
86
+ default_protocols = {}
87
+
88
+ for blueprint in data["blueprints"]:
89
+ for metamarker in blueprint["metamarkers"]:
90
+ protocol_type = metamarker.get("Type")
91
+ if protocol_type in protocols[blueprint["name"]]:
92
+ protocol_name = list(metamarker.keys())[0]
93
+ protocols[blueprint["name"]][protocol_type].append(protocol_name)
94
+
95
+ if blueprints.index(blueprint["name"]) == DEFAULT_BLUEPRINT_INDEX:
96
+ if protocol_type not in default_protocols:
97
+ default_protocols[protocol_type] = []
98
+ default_protocols[protocol_type].append(protocol_name)
99
+
100
+ return blueprints, protocols, data, default_protocols
101
+
102
+ blueprints, protocols, data, default_protocols = load_blueprints_and_protocols()
103
+
104
+ # Initialize protocol_scores
105
+ def initialize_scores():
106
+ global protocol_scores
107
+ protocol_scores = {protocol: 0 for blueprint in protocols
108
+ for category in protocols[blueprint]
109
+ for protocol in protocols[blueprint][category]}
110
+
111
+ initialize_scores()
112
+
113
+ # Initialize picked_blueprint_js with the default blueprint
114
+ picked_blueprint_js = data["blueprints"][DEFAULT_BLUEPRINT_INDEX]
115
+
116
+ def update_scores(message):
117
+ global protocol_scores, picked_blueprint_js
118
+
119
+ details = True
120
+ local = True
121
+
122
+ blueprint = picked_blueprint_js
123
+ print(f"Blueprint to API:", blueprint)
124
+
125
+ payload = {
126
+ "inputs": message,
127
+ "blueprint": [blueprint, 'BlueprintScore'],
128
+ "parameters": [{"details": details}, {"local": local}]
129
+ }
130
+
131
+ try:
132
+ response = requests.post(COGN_API_URL, headers=headers, json=payload)
133
+
134
+ if response.status_code == 200:
135
+ api_data = response.json()
136
+
137
+ if 'mw_score' in api_data[1]:
138
+ for protocol, score in api_data[1]['mw_score'].items():
139
+ if protocol in protocol_scores:
140
+ protocol_scores[protocol] = int(score * 100)
141
+ else:
142
+ print(f"Protocol '{protocol}' not found in protocol_scores")
143
+ else:
144
+ print(f"API request failed with status code {response.status_code}")
145
+ return {"error": "API request failed"}
146
+
147
+ except Exception as e:
148
+ print(f"API request failed: {str(e)}")
149
+ return {"error": "API request failed"}
150
+
151
+ return {"success": "Protocol scores updated successfully"}
152
+
153
+ def update_protocols(blueprint_name):
154
+ global protocol_scores, picked_blueprint_js
155
+
156
+ # Find the correct blueprint object
157
+ for blueprint in data["blueprints"]:
158
+ if blueprint["name"] == blueprint_name:
159
+ picked_blueprint_js = blueprint
160
+ break
161
+
162
+ if blueprint_name not in protocols:
163
+ return gr.update(value="")
164
+
165
+ css = """
166
+ <style>
167
+ .protocol-item {
168
+ display: flex;
169
+ align-items: center;
170
+ margin-bottom: 10px;
171
+ width: 100%;
172
+ }
173
+ .protocol-icon {
174
+ width: 24px;
175
+ height: 24px;
176
+ margin-right: 10px;
177
+ flex-shrink: 0;
178
+ }
179
+ .protocol-details {
180
+ display: flex;
181
+ align-items: center;
182
+ flex-grow: 1;
183
+ margin-right: 20px;
184
+ }
185
+ .protocol-name {
186
+ font-weight: bold;
187
+ margin-right: 10px;
188
+ }
189
+ .protocol-score {
190
+ font-size: 0.9em;
191
+ color: #666;
192
+ }
193
+ .progress-container {
194
+ width: 40px;
195
+ height: 40px;
196
+ position: relative;
197
+ flex-shrink: 0;
198
+ }
199
+ .progress-bar {
200
+ width: 100%;
201
+ height: 100%;
202
+ border-radius: 50%;
203
+ background: conic-gradient(#0014FF calc(var(--value) * 3.6deg), #ddd 0deg);
204
+ display: flex;
205
+ align-items: center;
206
+ justify-content: center;
207
+ }
208
+ .progress-bar::before {
209
+ content: "";
210
+ position: absolute;
211
+ inset: 5px;
212
+ background: white;
213
+ border-radius: 50%;
214
+ }
215
+ .progress-text {
216
+ position: absolute;
217
+ top: 50%;
218
+ left: 50%;
219
+ transform: translate(-50%, -50%);
220
+ font-size: 12px;
221
+ color: #333;
222
+ }
223
+ </style>
224
+ """
225
+ html_output = css
226
+ for title, categories in [("Advice", ["CT", "GP", "GS"]), ("Compliance", ["P"]), ("Insight", ["M"])]:
227
+ all_protocols = [(category, protocol) for category in categories for protocol in protocols[blueprint_name].get(category, [])]
228
+ if all_protocols:
229
+ html_output += f"<h3>{title}</h3>"
230
+ for category, protocol in all_protocols:
231
+ score = protocol_scores[protocol]
232
+ icon = load_svg_icon(category)
233
+ html_output += f'''
234
+ <div class="protocol-item">
235
+ <img src="{icon}" alt="{category}" class="protocol-icon" />
236
+ <div class="protocol-details">
237
+ <span class="protocol-name">{protocol}</span>
238
+ </div>
239
+ <div class="progress-container">
240
+ <div class="progress-bar" style="--value:{score};"></div>
241
+ <div class="progress-text">{score}</div>
242
+ </div>
243
+ </div>
244
+ '''
245
+ return gr.update(value=html_output)
246
+
247
+ def load_svg_icon(icon_type):
248
+ icon_cache = {}
249
+ if icon_type in icon_cache:
250
+ return icon_cache[icon_type]
251
+ icon_path = os.path.join("icons", f"{icon_type}.svg")
252
+ if os.path.exists(icon_path):
253
+ with open(icon_path, "rb") as f:
254
+ svg_content = f.read()
255
+ base64_icon = base64.b64encode(svg_content).decode("utf-8")
256
+ icon_cache[icon_type] = f'data:image/svg+xml;base64,{base64_icon}'
257
+ return icon_cache[icon_type]
258
+ return ""
259
+
260
+ def create_app():
261
+ global protocol_markdown, picked_blueprint_js
262
+ blueprints, protocols, data, default_protocols = load_blueprints_and_protocols()
263
+ initialize_scores()
264
+ picked_blueprint_js = data["blueprints"][DEFAULT_BLUEPRINT_INDEX]
265
+
266
+ is_running = False
267
+ history = []
268
+ conversation = []
269
+ message_index = 0
270
+
271
+ with gr.Blocks(theme=gr.themes.Base(), css="style.css") as app:
272
+
273
+ with gr.Row():
274
+ with gr.Column(scale=3):
275
+ blueprint_radio = gr.Radio(label="", choices=blueprints, type="index", value=DEFAULT_BLUEPRINT_INDEX, elem_classes="gr-radio-row")
276
+ protocol_markdown = gr.HTML(label="Associated Protocols:", value="")
277
+ with gr.Column(scale=0.1):
278
+ gr.HTML("")
279
+ with gr.Column(scale=3):
280
+ conversation_type = gr.Radio(choices=list(conversations.keys()), label="", value=DEFAULT_CONVERSATION_TYPE, elem_classes="gr-radio-row")
281
+ chat_display = gr.HTML()
282
+ with gr.Row():
283
+ start_button = gr.Button("▶")
284
+ pause_button = gr.Button("Pause")
285
+ resume_button = gr.Button("Resume")
286
+ stop_button = gr.Button("Stop")
287
+ num_messages = gr.Slider(minimum=2, maximum=20, value=10, step=1, label="Number of messages", visible=False)
288
+
289
+ # Helper functions to update chat and protocols
290
+ def conversation_type_change_handler(conversation_type):
291
+ stop_conversation()
292
+ return ""
293
+
294
+ def blueprint_change_handler(selected_index):
295
+ global picked_blueprint_js
296
+ blueprint_name = blueprints[selected_index]
297
+ return update_protocols(blueprint_name)
298
+
299
+ # Logic to handle the conversation loop
300
+ def run_conversation(conversation_type, num_messages):
301
+ nonlocal is_running, history, conversation, message_index
302
+
303
+ is_running = True # Start running the conversation
304
+ history = []
305
+ conversation = conversations[conversation_type][:num_messages]
306
+ message_index = 0
307
+
308
+ while is_running and message_index < len(conversation):
309
+ speaker, message = conversation[message_index]
310
+ history.append((speaker, message))
311
+ update_scores(message)
312
+ updated_protocols = update_protocols(picked_blueprint_js["name"])
313
+ message_index += 1
314
+ yield generate_chat_html(), updated_protocols
315
+ time.sleep(0.5) # Introduce a slight delay between messages
316
+
317
+ is_running = False # Reset after conversation completes
318
+
319
+ def generate_chat_html():
320
+ nonlocal history
321
+ chat_html = "<div class='chat-container'>"
322
+ for speaker, message in history:
323
+ chat_html += f"<div class='message {speaker.lower().replace(' ', '-')}'>"
324
+ chat_html += f"<strong>{speaker}:</strong> {message}"
325
+ chat_html += "</div>"
326
+ chat_html += "</div>"
327
+ return chat_html
328
+
329
+ def pause_conversation():
330
+ nonlocal is_running
331
+ is_running = False
332
+ return generate_chat_html(), protocol_markdown.value
333
+
334
+ def resume_conversation():
335
+ nonlocal is_running
336
+ if not is_running:
337
+ is_running = True
338
+ return generate_chat_html(), protocol_markdown.value
339
+
340
+ def stop_conversation():
341
+ nonlocal is_running, history
342
+ is_running = False
343
+ history = []
344
+ return "", protocol_markdown.value
345
+
346
+ # Gradio elements and events
347
+ blueprint_radio.change(
348
+ blueprint_change_handler,
349
+ inputs=[blueprint_radio],
350
+ outputs=[protocol_markdown]
351
+ )
352
+ conversation_type.change(
353
+ conversation_type_change_handler,
354
+ inputs=[conversation_type],
355
+ outputs=[chat_display]
356
+ )
357
+
358
+ start_button.click(
359
+ run_conversation,
360
+ inputs=[conversation_type, num_messages],
361
+ outputs=[chat_display, protocol_markdown]
362
+ )
363
+
364
+ pause_button.click(pause_conversation, outputs=[chat_display, protocol_markdown])
365
+ resume_button.click(resume_conversation, outputs=[chat_display, protocol_markdown])
366
+ stop_button.click(stop_conversation, outputs=[chat_display, protocol_markdown])
367
+
368
+ return app
369
+
370
+ if __name__ == "__main__":
371
+ app = create_app()
372
+ app.launch()
icons/CT.svg ADDED
icons/GP.svg ADDED
icons/GS.svg ADDED
icons/M.svg ADDED
icons/P.svg ADDED
requierements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ #huggingface_hub==0.22.2
2
+ redis==4.5.4
styles.css ADDED
@@ -0,0 +1,199 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Import Poppins font */
2
+ @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap');
3
+
4
+ /* Apply Poppins font to all elements */
5
+ * {
6
+ font-family: 'Poppins', sans-serif !important;
7
+ }
8
+
9
+ /* Button Styles */
10
+ button.svelte-cmf5ev {
11
+ background-color: #356EFF !important;
12
+ border-radius: 25px !important;
13
+ color: white !important;
14
+ }
15
+
16
+ button.svelte-cmf5ev:hover {
17
+ background-color: #0010CC !important;
18
+ }
19
+
20
+ /* Radio Button Styles */
21
+ .gr-radio-row {
22
+ display: flex !important;
23
+ flex-wrap: wrap !important;
24
+ gap: 10px !important;
25
+ }
26
+
27
+ .gr-radio-row input[type="radio"] {
28
+ display: none !important;
29
+ }
30
+
31
+ .gr-radio-row label {
32
+ display: inline-block !important;
33
+ padding: 10px 20px !important;
34
+ background-color: #ffffff !important;
35
+ border: 2px solid #0010CC !important;
36
+ border-radius: 25px !important;
37
+ cursor: pointer !important;
38
+ transition: all 0.3s ease !important;
39
+ }
40
+
41
+ /* Hover State */
42
+ .gr-radio-row label:hover {
43
+ background-color: #0010CC !important;
44
+ color: white !important;
45
+ }
46
+
47
+ .gr-radio-row input[type="radio"]:checked + label {
48
+ background-color: #0010CC !important;
49
+ border-color: #356EFF !important;
50
+ color: white !important;
51
+ }
52
+
53
+ /* Existing styles */
54
+ .gradio-group {
55
+ margin-bottom: 15px;
56
+ }
57
+
58
+ .gradio-slider {
59
+ width: 200px;
60
+ }
61
+
62
+ /* Protocol Display */
63
+ div.protocol-item {
64
+ display: inline-flex !important;
65
+ align-items: center;
66
+ margin-bottom: 10px;
67
+ width: 100%;
68
+ }
69
+
70
+ .protocol-icon {
71
+ width: 24px;
72
+ height: 24px;
73
+ margin-right: 10px;
74
+ flex-shrink: 0;
75
+ }
76
+
77
+ .protocol-details {
78
+ display: flex;
79
+ align-items: center;
80
+ flex-grow: 1;
81
+ margin-right: 20px;
82
+ }
83
+
84
+ .protocol-name {
85
+ font-weight: bold;
86
+ margin-right: 10px;
87
+ }
88
+
89
+ .protocol-score {
90
+ font-size: 0.8em;
91
+ color: #666;
92
+ }
93
+
94
+ /* Circular Progress Bar */
95
+ .progress-container {
96
+ width: 40px;
97
+ height: 40px;
98
+ position: relative;
99
+ flex-shrink: 0;
100
+ }
101
+
102
+ .progress-bar {
103
+ width: 100%;
104
+ height: 100%;
105
+ border-radius: 50%;
106
+ background: conic-gradient(#0014FF calc(var(--value) * 3.6deg), #ddd 0deg);
107
+ display: flex;
108
+ align-items: center;
109
+ justify-content: center;
110
+ }
111
+
112
+ .progress-bar::before {
113
+ content: "";
114
+ position: absolute;
115
+ inset: 5px;
116
+ background: white;
117
+ border-radius: 50%;
118
+ }
119
+
120
+ .progress-text {
121
+ position: absolute;
122
+ top: 50%;
123
+ left: 50%;
124
+ transform: translate(-50%, -50%);
125
+ font-size: 12px;
126
+ color: #333;
127
+ }
128
+
129
+ /* Chat Container Styles */
130
+ .chat-container {
131
+ height: 400px;
132
+ overflow-y: auto;
133
+ border: 1px solid #ccc;
134
+ border-radius: 10px;
135
+ padding: 15px;
136
+ margin-bottom: 20px;
137
+ background-color: #f9f9f9;
138
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
139
+ }
140
+
141
+ /* Ensure the chat section has an initial size */
142
+ #chat_display {
143
+ min-height: 400px;
144
+ width: 100%;
145
+ display: block !important;
146
+ }
147
+
148
+ /* Message Styles */
149
+ .message {
150
+ margin-bottom: 15px;
151
+ padding: 10px 15px;
152
+ border-radius: 18px;
153
+ max-width: 80%;
154
+ position: relative;
155
+ clear: both;
156
+ }
157
+
158
+ .banker, .customer-service, .employee-1 {
159
+ background-color: #E3F2FD;
160
+ color: #1565C0;
161
+ float: left;
162
+ border-bottom-left-radius: 5px;
163
+ }
164
+
165
+ .client, .customer, .employee-2 {
166
+ background-color: #E8EAF6;
167
+ color: #3F51B5;
168
+ float: right;
169
+ border-bottom-right-radius: 5px;
170
+ }
171
+
172
+ /* Add a subtle shadow to messages for depth */
173
+ .message::after {
174
+ content: '';
175
+ position: absolute;
176
+ bottom: 0;
177
+ width: 0;
178
+ height: 0;
179
+ border: 8px solid transparent;
180
+ }
181
+
182
+ .banker::after, .customer-service::after, .employee-1::after {
183
+ left: -8px;
184
+ border-right-color: #E3F2FD;
185
+ border-bottom-color: #E3F2FD;
186
+ }
187
+
188
+ .client::after, .customer::after, .employee-2::after {
189
+ right: -8px;
190
+ border-left-color: #E8EAF6;
191
+ border-bottom-color: #E8EAF6;
192
+ }
193
+
194
+ /* Style for the sender's name */
195
+ .message strong {
196
+ display: block;
197
+ margin-bottom: 5px;
198
+ font-weight: 600;
199
+ }