lingyit1108 commited on
Commit
4df8c11
0 Parent(s):

first commit

Browse files
.DS_Store ADDED
Binary file (6.15 kB). View file
 
README.md ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: agent_persona
3
+ emoji: 🔥
4
+ colorFrom: blue
5
+ colorTo: yellow
6
+ sdk: streamlit
7
+ python_version: 3.12.4
8
+ sdk_version: 1.37.1
9
+ app_file: financial_consultant_persona.py
10
+ pinned: false
11
+ license: mit
12
+ ---
13
+
14
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces#reference
ai_assistant.py ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from openai import OpenAI
2
+
3
+ system_prompt = """
4
+ System Prompt for Insurance Sales Assistant:
5
+
6
+ You are a smart and efficient AI assistant designed to support insurance sales agents by providing critical information about customers. Your primary function is to assist agents in understanding customer needs, identifying sales opportunities, and making informed recommendations. Use the following structured information to deliver concise, actionable insights.
7
+
8
+ Customer information that will be provided as follows:
9
+
10
+ 1. Opportunities
11
+ - Current coverage levels across different insurance categories.
12
+ - Likelihood of purchasing additional coverage in various categories.
13
+
14
+ 2. Recent Engagements
15
+ - Historical interactions with the customer, including financial needs analyses (FNA) and details of previously purchased policies.
16
+
17
+ 3. Insights
18
+ - Product recommendations based on customer needs and gaps in coverage.
19
+ - Top coverage gaps according to Life Insurance Association (LIA) standards.
20
+ - Propensity to buy score and its interpretation.
21
+
22
+ 4. Predictive Model Reasonings
23
+ - Detailed model insights, including specific financial targets, existing assets, and coverage details.
24
+
25
+ How to Respond:
26
+ - Prioritize customer needs: Focus on areas where there are significant coverage gaps and a high likelihood to buy.
27
+ - Be specific: Provide precise recommendations on products that match the customer’s needs, supported by data from recent engagements and model reasonings.
28
+ - Use plain language: Avoid jargon; explain insurance terms simply and clearly.
29
+ - Highlight critical insights: Emphasize top coverage gaps, high-propensity categories, and any high-priority customer goals.
30
+ - Maintain a customer-centric approach: Always consider the customer’s history, current coverage, and stated preferences in your recommendations.
31
+ - Pretend you are a very good insurance sales agent who can provide a very convincing pitch based on customer needs.
32
+ - Don't need to respond in email style.
33
+ - Provide actionable steps to the financial consultant in how to approach customer based on what we have known so far.
34
+ """.strip()
35
+
36
+ def get_ai_response(input_prompt):
37
+ final_prompt = system_prompt + \
38
+ "\n\n" + \
39
+ "Here are the information about the customer" + \
40
+ "\n\n" + \
41
+ input_prompt
42
+
43
+ client = OpenAI()
44
+ ai_stream = client.chat.completions.create(
45
+ model="gpt-4o-mini",
46
+ messages=[{"role": "user", "content": final_prompt}],
47
+ stream=True,
48
+ max_tokens=16384
49
+ )
50
+ return ai_stream
bin/clean.sh ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ find . -name __pycache__ | xargs rm -rf
4
+ find . -name .pytest_cache | xargs rm -rf
5
+ find . -name .ipynb_checkpoints | xargs rm -rf
data/yoda_data.csv ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cust_name,prod_cat,cov_level,prop_score,recom_products
2
+ "Wong Ling Yit","Protection",2,0.8,"PRUActive Life III"
3
+ "Wong Ling Yit","CI",1,0.1,"PRUActive Protect"
4
+ "Wong Ling Yit","Medical",3,0.2,"PRUShield Premier"
5
+ "Wong Ling Yit","Investment",4,0.5,"PRUVantage Assure II"
6
+ "Wong Ling Yit","Savings",5,0.2,"PRUActive Saver III"
7
+ "Wong Ling Yit","Retirement",1,0.3,"PRUActive Retirement II"
8
+ "Wong Ling Yit","Legacy",2,0.4,"PRULife Vantage Achiever Prime Series"
9
+ "Wei Shan Chin","Protection",1,0.3,"PRUActive Life III"
10
+ "Wei Shan Chin","CI",3,0.9,"PRUActive Protect"
11
+ "Wei Shan Chin","Medical",4,0.2,"PRUShield Premier"
12
+ "Wei Shan Chin","Investment",2,0.5,"PRUVantage Assure II"
13
+ "Wei Shan Chin","Savings",2,0.4,"PRUActive Saver III"
14
+ "Wei Shan Chin","Retirement",1,0.3,"PRUActive Retirement II"
15
+ "Wei Shan Chin","Legacy",5,0.8,"PRULife Vantage Achiever Prime Series"
16
+ "Darek Cieslinski","Protection",2,0.8,"PRUActive Life III"
17
+ "Darek Cieslinski","CI",3,0.5,"PRUActive Protect"
18
+ "Darek Cieslinski","Medical",2.5,0.2,"PRUShield Premier"
19
+ "Darek Cieslinski","Investment",5,0.3,"PRUVantage Assure II"
20
+ "Darek Cieslinski","Savings",4,0.6,"PRUActive Saver III"
21
+ "Darek Cieslinski","Retirement",1,0.9,"PRUActive Retirement II"
22
+ "Darek Cieslinski","Legacy",4,0.3,"PRULife Vantage Achiever Prime Series"
data/yoda_poe.csv ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ cust_name,poe_findings
2
+ "Wong Ling Yit","Protection (gap: $142,257), customer also indicated protection as priority in POE"
3
+ "Wei Shan Chin","Critical Illness (gap: $41,876), customer also indicated protection as priority in POE"
4
+ "Darek Cieslinski","Retirement (gap: $1,249,246), customer also indicated retirement as priority in POE"
data/yoda_reasonings.csv ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cust_name,r_index,reasonings
2
+ "Wong Ling Yit",1,"Total Sum Assured: $326,700"
3
+ "Wong Ling Yit",2,"Risk Profile Q6 (How many years are you away from your retirement?): 15 years or more"
4
+ "Wong Ling Yit",3,"No. of Inforced Policies: 7"
5
+ "Wong Ling Yit",4,"No. of Policies Bought Past 3 Years: 2"
6
+ "Wong Ling Yit",5,"Housing District: 03 - Queenstown, Tiong Bahru"
7
+ "Wei Shan Chin",1,"Has A&H Policies: Yes"
8
+ "Wei Shan Chin",2,"Has Whole Life (Non-Unit Linked) Policies: Yes"
9
+ "Wei Shan Chin",3,"No. of Policies Bought Past 3 Years: 2"
10
+ "Wei Shan Chin",4,"No. of Inforced Policies: 7"
11
+ "Wei Shan Chin",5,"Housing District: 03 - Queenstown, Tiong Bahru"
12
+ "Darek Cieslinski",1,"Customer Retirement Accumulation Target: $2,403,124"
13
+ "Darek Cieslinski",2,"Has Endowment/Savings (Non-Unit Linked) Policies: Yes"
14
+ "Darek Cieslinski",3,"Customer Total Asset: $150,000"
15
+ "Darek Cieslinski",4,"Total Sum Assured: $326,700"
16
+ "Darek Cieslinski",5,"Age: 34"
financial_consultant_persona.py ADDED
@@ -0,0 +1,265 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import plotly.express as px
2
+ import streamlit as st
3
+ import pandas as pd
4
+ from ai_assistant import get_ai_response
5
+
6
+ def get_score_rating(s):
7
+ if s >= 0.75:
8
+ return "HIGH"
9
+ elif 0.4 <= s < 0.75:
10
+ return "MEDIUM"
11
+ elif s < 0.4:
12
+ return "LOW"
13
+
14
+ def get_cov_rating(c):
15
+ if c >= 4:
16
+ return "Sufficient Coverage"
17
+ elif 2 <= c < 4:
18
+ return "Insufficient Coverage"
19
+ elif c < 2:
20
+ return "Significantly Insufficient Coverage"
21
+
22
+ @st.cache_data
23
+ def get_cust_data_dict(cust_name="Wong Ling Yit"):
24
+
25
+ data = pd.read_csv("data/yoda_data.csv")
26
+ poe_data = pd.read_csv("data/yoda_poe.csv")
27
+ reasons_df = pd.read_csv("data/yoda_reasonings.csv")
28
+
29
+ temp = data[data["cust_name"] == cust_name]
30
+ temp_poe = poe_data[poe_data["cust_name"] == cust_name]
31
+ temp_reason = reasons_df[reasons_df["cust_name"] == cust_name]
32
+
33
+ if len(temp) != 7 or \
34
+ len(temp_poe) != 1 or \
35
+ len(temp_reason) != 5:
36
+ temp = data[data["cust_name"] == "Wong Ling Yit"]
37
+ temp_poe = poe_data[poe_data["cust_name"] == "Wong Ling Yit"]
38
+ temp_reason = reasons_df[reasons_df["cust_name"] == "Wong Ling Yit"]
39
+
40
+ temp = temp.rename(columns={
41
+ "prod_cat": "Product Category",
42
+ "cov_level": "Coverage Level",
43
+ "prop_score": "Score",
44
+ "recom_products": "Recommended Product"
45
+ })
46
+ temp["Coverage Rating"] = temp["Coverage Level"].apply(
47
+ lambda c: get_cov_rating(c)
48
+ )
49
+ temp["Score Rating"] = temp["Score"].apply(
50
+ lambda s: get_score_rating(s)
51
+ )
52
+ cov_rating_map = dict(zip(
53
+ temp["Product Category"],
54
+ temp["Coverage Rating"]
55
+ ))
56
+ score_rating_map = dict(zip(
57
+ temp["Product Category"],
58
+ temp["Score Rating"]
59
+ ))
60
+
61
+ radar_df = pd.DataFrame({
62
+ "Product Category": [
63
+ "Retirement",
64
+ "Protection",
65
+ "Savings",
66
+ "CI",
67
+ "Investment",
68
+ "Legacy",
69
+ "Medical"
70
+ ]
71
+ })
72
+ radar_df = pd.merge(radar_df, temp, on="Product Category", how="inner")
73
+ temp = temp.sort_values("Score", ascending=False).reset_index(drop=True)
74
+
75
+ top_products = temp[:3]["Recommended Product"].tolist()
76
+
77
+ top_score = temp.iloc[0]["Score"]
78
+ score_rating = get_score_rating(top_score)
79
+ top_score_msg = f"{top_score:.2f} - {score_rating}"
80
+
81
+ poe_findings = temp_poe.iloc[0]["poe_findings"]
82
+
83
+ temp_reason = temp_reason.sort_values("r_index", ascending=True).reset_index(drop=True)
84
+ temp_reason_ls = temp_reason["reasonings"].tolist()
85
+
86
+ return (radar_df, temp, top_products, top_score_msg,
87
+ poe_findings, temp_reason_ls,
88
+ cov_rating_map, score_rating_map)
89
+
90
+ st.title("Persona: Financial Consultant - Leads follow-up")
91
+ st.header("Lead selection", divider="blue")
92
+ st.subheader("My customers - Hot Lead🔥")
93
+
94
+ cust_option = st.selectbox(
95
+ label="Customer options",
96
+ options=(
97
+ "Darek Cieslinski", "Anthony Finch", "Ariel CL Ong",
98
+ "Deren Meng", "Prabhavathi Bharadwaj", "Tan Li Lin",
99
+ "Wei Shan Chin", "Wong Chen Mey", "Wong Ling Yit"),
100
+ label_visibility="collapsed"
101
+ )
102
+
103
+ ## "Wei Shan Chin", "Wong Chen Mey", "Tan Li Lin", "Prabhavathi Bharadwaj",
104
+ ## "Deren Meng", "Anthony Finch", "Ariel CL Ong", "Darek Cieslinski"
105
+ data_pack = get_cust_data_dict(cust_name=cust_option)
106
+ radar_df = data_pack[0]
107
+ df = data_pack[1]
108
+ top_products = data_pack[2]
109
+ score_msg = data_pack[3]
110
+ poe_findings = data_pack[4]
111
+ model_reasons = data_pack[5]
112
+ cov_rating_map = data_pack[6]
113
+ score_rating_map = data_pack[7]
114
+ view_1, view_2 = st.columns(2, gap="medium")
115
+
116
+ with view_1:
117
+ st.subheader("Coverage level")
118
+ fig = px.line_polar(radar_df, r="Coverage Level",
119
+ theta="Product Category", line_close=True)
120
+ fig.update_layout(
121
+ margin=dict(l=60, r=40, t=20, b=20),
122
+ )
123
+ fig.update_traces(fill="toself")
124
+
125
+ st.plotly_chart(fig, theme="streamlit", use_container_width=True)
126
+
127
+ with view_2:
128
+ st.subheader("Propensity to buy")
129
+ fig = px.bar(df, x="Product Category", y="Score")
130
+ fig.update_layout(
131
+ margin=dict(l=60, r=40, t=50, b=20),
132
+ )
133
+
134
+ st.plotly_chart(fig, theme="streamlit", use_container_width=True)
135
+
136
+ st.write("")
137
+ st.write("***Expand to see more details.***")
138
+ with st.expander("Recent engagement.."):
139
+ st.subheader("Financial Needs Analysis (FNA)", divider="blue")
140
+ st.write("")
141
+ st.write("Date: 15/06/2022 - Protection need for family")
142
+ st.write("")
143
+ st.write("Date: 18/02/2019 - Critical Illness coverage gap of S$50,000")
144
+ st.divider()
145
+
146
+ st.subheader("Last policies purchased", divider="blue")
147
+ st.write("")
148
+ st.write("Date: 02/12/2017 - PRUActive LinkGuard purchased for self")
149
+ st.write("")
150
+ st.write("Date: 08/11/2013 - PRUWealth Plus (SGD) purchased for daughter")
151
+ st.divider()
152
+
153
+ st.write("")
154
+ st.header("Insights", divider="blue")
155
+ st.markdown(
156
+ f"""
157
+ **Recommended Products:**
158
+ - {top_products[0]}
159
+ - {top_products[1]}
160
+ - {top_products[2]}
161
+
162
+ **Top LIA Coverage Gap:**
163
+ - {poe_findings}
164
+
165
+ **Propensity to buy score:**
166
+ - {score_msg}
167
+ """
168
+ )
169
+
170
+ st.header("Reasonings", divider="blue")
171
+ st.write("")
172
+ st.markdown(
173
+ f"""
174
+ **Model Reasonings:**
175
+ - {model_reasons[0]}
176
+ - {model_reasons[1]}
177
+ - {model_reasons[2]}
178
+ - {model_reasons[3]}
179
+ - {model_reasons[4]}
180
+ """
181
+ )
182
+ st.write("")
183
+
184
+ st.header("Sales pitch", divider="blue")
185
+ list_of_cust_tabs = st.tabs(tabs=["Summary", "Assistant"])
186
+ summary_tab = list_of_cust_tabs[0]
187
+ pitch_tab = list_of_cust_tabs[1]
188
+
189
+ about_this_cust = f"""
190
+ Opportunities
191
+ ===============
192
+ In terms of current coverage level,
193
+ - Retirement: {cov_rating_map["Retirement"]}
194
+ - Protection: {cov_rating_map["Protection"]}
195
+ - Savings: {cov_rating_map["Savings"]}
196
+ - Critical Illness: {cov_rating_map["CI"]}
197
+ - Investment: {cov_rating_map["Investment"]}
198
+ - Legacy: {cov_rating_map["Legacy"]}
199
+ - Medical: {cov_rating_map["Medical"]}
200
+
201
+ In terms of likelihood to buy,
202
+ - Retirement: {score_rating_map["Retirement"]}
203
+ - Protection: {score_rating_map["Protection"]}
204
+ - Savings: {score_rating_map["Savings"]}
205
+ - Critical Illness: {score_rating_map["CI"]}
206
+ - Investment: {score_rating_map["Investment"]}
207
+ - Legacy: {score_rating_map["Legacy"]}
208
+ - Medical: {score_rating_map["Medical"]}
209
+
210
+ Recent engagements
211
+ ===================
212
+ Financial Needs Analysis (FNA):
213
+ Date: 15/06/2022 - Protection need for family
214
+ Date: 18/02/2019 - Critical Illness coverage gap of S$50,000
215
+
216
+ Last policies purchased:
217
+ Date: 02/12/2017 - PRUActive LinkGuard purchased for self
218
+ Date: 08/11/2013 - PRUWealth Plus (SGD) purchased for daughter
219
+
220
+ Insights
221
+ =========
222
+ Recommended Products:
223
+ - {top_products[0]}
224
+ - {top_products[1]}
225
+ - {top_products[2]}
226
+
227
+ Top LIA Coverage Gap:
228
+ - {poe_findings}
229
+
230
+ Propensity to buy score: {score_msg}
231
+
232
+ Predictive model reasonings
233
+ ===========================
234
+ - {model_reasons[0]}
235
+ - {model_reasons[1]}
236
+ - {model_reasons[2]}
237
+ - {model_reasons[3]}
238
+ - {model_reasons[4]}
239
+ """.strip()
240
+
241
+ with summary_tab:
242
+ txt = st.text_area(
243
+ "About this customer",
244
+ about_this_cust,
245
+ height=500
246
+ )
247
+
248
+ with pitch_tab:
249
+ st.write("Suggest sales pitch for this customer")
250
+ generate_button = st.button("Generate")
251
+ if generate_button:
252
+ placeholder = st.empty()
253
+ full_response = ""
254
+
255
+ stream = get_ai_response(about_this_cust)
256
+ for chunk in stream:
257
+ token = chunk.choices[0].delta.content
258
+ if token is not None:
259
+ full_response += token
260
+ # full_response += token.replace("\n", " \n") \
261
+ # .replace("$", "\$") \
262
+ # .replace("\[", "$$")
263
+ placeholder.markdown(full_response)
264
+ placeholder.markdown(full_response)
265
+ print(full_response)
requirements.txt ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ altair==5.3.0
2
+ annotated-types==0.7.0
3
+ anyio==4.4.0
4
+ attrs==24.2.0
5
+ blinker==1.8.2
6
+ cachetools==5.4.0
7
+ certifi==2024.7.4
8
+ charset-normalizer==3.3.2
9
+ click==8.1.7
10
+ distro==1.9.0
11
+ gitdb==4.0.11
12
+ GitPython==3.1.43
13
+ h11==0.14.0
14
+ httpcore==1.0.5
15
+ httpx==0.27.0
16
+ idna==3.7
17
+ importlib-metadata==6.11.0
18
+ Jinja2==3.1.4
19
+ jiter==0.5.0
20
+ jsonschema==4.23.0
21
+ jsonschema-specifications==2023.12.1
22
+ markdown-it-py==3.0.0
23
+ MarkupSafe==2.1.5
24
+ mdurl==0.1.2
25
+ numpy==1.26.4
26
+ openai==1.40.2
27
+ packaging==23.2
28
+ pandas==2.2.2
29
+ pillow==10.4.0
30
+ plotly==5.23.0
31
+ protobuf==4.25.4
32
+ pyarrow==17.0.0
33
+ pydantic==2.8.2
34
+ pydantic_core==2.20.1
35
+ pydeck==0.9.1
36
+ Pygments==2.18.0
37
+ python-dateutil==2.9.0.post0
38
+ pytz==2024.1
39
+ referencing==0.35.1
40
+ requests==2.32.3
41
+ rich==13.7.1
42
+ rpds-py==0.20.0
43
+ setuptools==72.1.0
44
+ six==1.16.0
45
+ smmap==5.0.1
46
+ sniffio==1.3.1
47
+ streamlit==1.37.1
48
+ tenacity==8.5.0
49
+ toml==0.10.2
50
+ toolz==0.12.1
51
+ tornado==6.4.1
52
+ tqdm==4.66.5
53
+ typing_extensions==4.12.2
54
+ tzdata==2024.1
55
+ tzlocal==5.2
56
+ urllib3==2.2.2
57
+ validators==0.33.0
58
+ wheel==0.43.0
59
+ zipp==3.19.2