ramisn commited on
Commit
6941040
·
verified ·
1 Parent(s): efd849d

Initial commit

Browse files
Files changed (1) hide show
  1. app.py +365 -0
app.py ADDED
@@ -0,0 +1,365 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import streamlit as st
3
+ import pandas as pd
4
+ from datetime import datetime, timedelta
5
+ import time
6
+ from huggingface_hub import InferenceClient
7
+ import dotenv
8
+
9
+ # Load environment variables
10
+ dotenv.load_dotenv()
11
+
12
+ # Set page configuration
13
+ st.set_page_config(
14
+ page_title="Debt Collection AI",
15
+ page_icon="💰",
16
+ layout="wide"
17
+ )
18
+
19
+ # Custom CSS for styling
20
+ st.markdown("""
21
+ <style>
22
+ .main-header {
23
+ font-size: 2.5rem;
24
+ color: #1E3A8A;
25
+ text-align: center;
26
+ margin-bottom: 2rem;
27
+ font-weight: bold;
28
+ text-shadow: 1px 1px 2px rgba(0,0,0,0.1);
29
+ }
30
+ .agent-button {
31
+ background-color: #3B82F6;
32
+ color: white;
33
+ padding: 1rem;
34
+ border-radius: 10px;
35
+ text-align: center;
36
+ margin: 1rem 0;
37
+ cursor: pointer;
38
+ transition: all 0.3s;
39
+ }
40
+ .agent-button:hover {
41
+ background-color: #1E40AF;
42
+ transform: translateY(-2px);
43
+ box-shadow: 0 4px 6px rgba(0,0,0,0.1);
44
+ }
45
+ .result-container {
46
+ background-color: #F3F4F6;
47
+ padding: 1.5rem;
48
+ border-radius: 10px;
49
+ margin-top: 1.5rem;
50
+ border-left: 5px solid #3B82F6;
51
+ }
52
+ .sidebar-item {
53
+ padding: 0.75rem;
54
+ border-radius: 5px;
55
+ margin-bottom: 0.5rem;
56
+ cursor: pointer;
57
+ transition: background-color 0.2s;
58
+ }
59
+ .sidebar-item:hover {
60
+ background-color: #E5E7EB;
61
+ }
62
+ .sidebar-item.active {
63
+ background-color: #DBEAFE;
64
+ font-weight: bold;
65
+ }
66
+ .metric-card {
67
+ background-color: #EFF6FF;
68
+ padding: 1rem;
69
+ border-radius: 8px;
70
+ text-align: center;
71
+ box-shadow: 0 2px 4px rgba(0,0,0,0.05);
72
+ }
73
+ .metric-value {
74
+ font-size: 1.5rem;
75
+ font-weight: bold;
76
+ color: #1E40AF;
77
+ }
78
+ .metric-label {
79
+ font-size: 0.9rem;
80
+ color: #6B7280;
81
+ }
82
+ </style>
83
+ """, unsafe_allow_html=True)
84
+
85
+ # Configuration
86
+ MODEL_NAME = "meta-llama/Meta-Llama-3-8B-Instruct"
87
+ HF_API_KEY = os.getenv("HF_API_KEY")
88
+ COMPLIANCE_RULES = {"prohibited_words": ["sue", "arrest", "threaten"], "max_installment_ratio": 0.3}
89
+
90
+ # Initialize Hugging Face client
91
+ @st.cache_resource
92
+ def get_client():
93
+ return InferenceClient(
94
+ model=MODEL_NAME,
95
+ token=HF_API_KEY
96
+ )
97
+
98
+ # Sample data (Mock Database)
99
+ DEBTORS = {
100
+ 1000: {
101
+ "debtor_id": 1000,
102
+ "name": "Rami",
103
+ "age": 35,
104
+ "preferred_language": "English",
105
+ "preferred_channel": "Email",
106
+ "income": 60000,
107
+ "outstanding_balance": 1500,
108
+ "installments": 15,
109
+ "last_payment_date": "2023-11-01",
110
+ "dispute_history": []
111
+ },
112
+ 1001: {
113
+ "debtor_id": 1001,
114
+ "name": "Jane Doe",
115
+ "age": 35,
116
+ "preferred_language": "English",
117
+ "preferred_channel": "SMS",
118
+ "income": 45000,
119
+ "outstanding_balance": 2500,
120
+ "installments": 12,
121
+ "last_payment_date": "2023-10-15",
122
+ "dispute_history": ["Billing error on 2023-09-01"]
123
+ }
124
+ }
125
+
126
+ # Business Logic Functions
127
+ def optimize_channel(debtor_data: dict) -> dict:
128
+ age = debtor_data["age"]
129
+ return {
130
+ "channel": "SMS" if age < 35 else "Email",
131
+ "best_time": "18:00-20:00" if age < 35 else "09:00-12:00"
132
+ }
133
+
134
+ def generate_message(debtor_data: dict) -> str:
135
+ try:
136
+ client = get_client()
137
+
138
+ prompt = f"""<|begin_of_text|>
139
+ <|start_header_id|>system<|end_header_id|>
140
+ Generate a friendly debt collection message in {debtor_data['preferred_language']}.
141
+ Avoid these words: {COMPLIANCE_RULES['prohibited_words']}.<|eot_id|>
142
+
143
+ <|start_header_id|>user<|end_header_id|>
144
+ Debtor: {debtor_data['name']}
145
+ Last Payment: {debtor_data['last_payment_date']}
146
+ Balance: ${debtor_data['outstanding_balance']}<|eot_id|>
147
+
148
+ <|start_header_id|>assistant<|end_header_id|>
149
+ """
150
+
151
+ response = client.text_generation(
152
+ prompt,
153
+ max_new_tokens=200,
154
+ temperature=0.7
155
+ )
156
+ print(response)
157
+ return response.strip()
158
+
159
+ except Exception as e:
160
+ st.error(f"Error generating message: {str(e)}")
161
+ return "Hello, this is a friendly reminder about your outstanding balance. Please contact us to discuss payment options."
162
+
163
+ def calculate_payment_plan(debtor_data: dict) -> dict:
164
+ max_payment = debtor_data["income"] * COMPLIANCE_RULES["max_installment_ratio"]
165
+ installments = debtor_data["installments"]
166
+ return {
167
+ "monthly_payment": round(debtor_data["outstanding_balance"] / installments, 2),
168
+ "duration_months": installments,
169
+ "due_date": (datetime.now() + timedelta(days=15)).strftime("%Y-%m-%d")
170
+ }
171
+
172
+ def generate_negotiation_strategy(debtor_data: dict) -> str:
173
+ try:
174
+ client = get_client()
175
+
176
+ prompt = f"""<|begin_of_text|>
177
+ <|start_header_id|>system<|end_header_id|>
178
+ Generate a negotiation strategy for a debt collection agent. Include personalized payment options and dispute handling recommendations.<|eot_id|>
179
+
180
+ <|start_header_id|>user<|end_header_id|>
181
+ Debtor: {debtor_data['name']}
182
+ Income: ${debtor_data['income']}
183
+ Balance: ${debtor_data['outstanding_balance']}
184
+ Installments: {debtor_data['installments']}
185
+ Dispute History: {debtor_data['dispute_history'] if debtor_data['dispute_history'] else "None"}<|eot_id|>
186
+
187
+ <|start_header_id|>assistant<|end_header_id|>
188
+ """
189
+
190
+ response = client.text_generation(
191
+ prompt,
192
+ max_new_tokens=300,
193
+ temperature=0.7
194
+ )
195
+ print(response)
196
+ return response.strip()
197
+
198
+ except Exception as e:
199
+ st.error(f"Error generating negotiation strategy: {str(e)}")
200
+ return "Recommend standard payment plan with flexible options. Address any disputes promptly and professionally."
201
+
202
+ def get_message_response(debtor_id):
203
+ debtor = DEBTORS.get(debtor_id)
204
+ if not debtor:
205
+ return {"error": "Debtor not found"}
206
+
207
+ channel_info = optimize_channel(debtor)
208
+ return {
209
+ "debtor_id": debtor_id,
210
+ "message": generate_message(debtor),
211
+ "channel": channel_info["channel"],
212
+ "send_time": f"{datetime.now().date()}T{channel_info['best_time']}"
213
+ }
214
+
215
+ def get_payment_plan_response(debtor_id):
216
+ debtor = DEBTORS.get(debtor_id)
217
+ if not debtor:
218
+ return {"error": "Debtor not found"}
219
+
220
+ return {
221
+ "debtor_id": debtor_id,
222
+ "payment_plan": calculate_payment_plan(debtor),
223
+ "negotiation_strategy": generate_negotiation_strategy(debtor)
224
+ }
225
+
226
+ # Initialize session state
227
+ if 'selected_debtor_id' not in st.session_state:
228
+ st.session_state.selected_debtor_id = None
229
+ if 'message_response' not in st.session_state:
230
+ st.session_state.message_response = None
231
+ if 'payment_plan' not in st.session_state:
232
+ st.session_state.payment_plan = None
233
+
234
+ # Calculate total outstanding balance
235
+ total_outstanding = sum(debtor["outstanding_balance"] for debtor in DEBTORS.values())
236
+
237
+ # Check for API key
238
+ if not HF_API_KEY:
239
+ st.error("Hugging Face API key not found. Please set the HF_API_KEY environment variable.")
240
+ st.stop()
241
+
242
+ # Sidebar - Debtor selection
243
+ with st.sidebar:
244
+ st.markdown("<h2 style='text-align: center;'>Debtors</h2>", unsafe_allow_html=True)
245
+ st.markdown("<hr>", unsafe_allow_html=True)
246
+
247
+ # Using buttons for debtor selection
248
+ for debtor_id, debtor in DEBTORS.items():
249
+ if st.button(f"{debtor['name']} (ID: {debtor_id})", key=f"select_{debtor_id}"):
250
+ st.session_state.selected_debtor_id = debtor_id
251
+ st.session_state.message_response = None
252
+ st.session_state.payment_plan = None
253
+
254
+ st.markdown("<hr>", unsafe_allow_html=True)
255
+
256
+ # Metrics
257
+ st.markdown("<h3 style='text-align: center;'>Summary</h3>", unsafe_allow_html=True)
258
+ st.markdown(f"""
259
+ <div class="metric-card">
260
+ <div class="metric-value">{len(DEBTORS)}</div>
261
+ <div class="metric-label">Active Debtors</div>
262
+ </div>
263
+ """, unsafe_allow_html=True)
264
+ st.markdown(f"""
265
+ <div class="metric-card" style="margin-top: 1rem;">
266
+ <div class="metric-value">${total_outstanding}</div>
267
+ <div class="metric-label">Total Outstanding</div>
268
+ </div>
269
+ """, unsafe_allow_html=True)
270
+
271
+ # Model info
272
+ st.markdown("<hr>", unsafe_allow_html=True)
273
+ st.markdown("<h3 style='text-align: center;'>Model</h3>", unsafe_allow_html=True)
274
+ st.markdown(f"**Using:** {MODEL_NAME}")
275
+
276
+ # Main content
277
+ st.markdown("<h1 class='main-header'>Debt Collection AI</h1>", unsafe_allow_html=True)
278
+
279
+ # Display selected debtor information
280
+ if st.session_state.selected_debtor_id:
281
+ debtor = DEBTORS[st.session_state.selected_debtor_id]
282
+
283
+ # Create columns for debtor info
284
+ col1, col2, col3 = st.columns(3)
285
+ with col1:
286
+ st.markdown(f"### {debtor['name']}")
287
+ st.markdown(f"**ID:** {debtor['debtor_id']}")
288
+ st.markdown(f"**Age:** {debtor['age']}")
289
+ with col2:
290
+ st.markdown("### Contact Info")
291
+ st.markdown(f"**Language:** {debtor['preferred_language']}")
292
+ st.markdown(f"**Channel:** {debtor['preferred_channel']}")
293
+ with col3:
294
+ st.markdown("### Financial Info")
295
+ st.markdown(f"**Balance:** ${debtor['outstanding_balance']}")
296
+ st.markdown(f"**Installments:** {debtor['installments']}")
297
+ st.markdown(f"**Last Payment:** {debtor['last_payment_date']}")
298
+
299
+ st.markdown("<hr>", unsafe_allow_html=True)
300
+
301
+ # Action buttons
302
+ col1, col2 = st.columns(2)
303
+
304
+ with col1:
305
+ st.markdown("""
306
+ <div class="agent-button" id="message-btn">
307
+ <h3>Agent 1: Empathy-Driven Communicator</h3>
308
+ <p>Create an empathetic collection message</p>
309
+ </div>
310
+ """, unsafe_allow_html=True)
311
+ if st.button("Generate Message", key="gen_message"):
312
+ with st.spinner("Agent 1 is generating a message..."):
313
+ # Get response
314
+ response = get_message_response(st.session_state.selected_debtor_id)
315
+ if response and "error" not in response:
316
+ st.session_state.message_response = response
317
+ st.session_state.payment_plan = None
318
+ else:
319
+ st.error(response.get("error", "Unknown error occurred"))
320
+
321
+ with col2:
322
+ st.markdown("""
323
+ <div class="agent-button" id="payment-btn">
324
+ <h3>Agent 2: Negotiation & Payment Planner</h3>
325
+ <p>Create a personalized payment plan</p>
326
+ </div>
327
+ """, unsafe_allow_html=True)
328
+ if st.button("Calculate Plan", key="calc_plan"):
329
+ with st.spinner("Agent 2 is analyzing and planning..."):
330
+ # Get response
331
+ response = get_payment_plan_response(st.session_state.selected_debtor_id)
332
+ if response and "error" not in response:
333
+ st.session_state.payment_plan = response
334
+ st.session_state.message_response = None
335
+ else:
336
+ st.error(response.get("error", "Unknown error occurred"))
337
+
338
+ # Display results
339
+ if st.session_state.message_response:
340
+ st.markdown("<div class='result-container'>", unsafe_allow_html=True)
341
+ st.markdown("### Agent 1: Empathy-Driven Communication")
342
+ st.markdown(f"**Channel:** {st.session_state.message_response['channel']}")
343
+ st.markdown(f"**Best Send Time:** {st.session_state.message_response['send_time'].split('T')[1]}")
344
+ st.markdown("#### Message Content:")
345
+ st.markdown(f"```\n{st.session_state.message_response['message']}\n```")
346
+ st.markdown("</div>", unsafe_allow_html=True)
347
+
348
+ elif st.session_state.payment_plan:
349
+ st.markdown("<div class='result-container'>", unsafe_allow_html=True)
350
+ st.markdown("### Agent 2: Negotiation & Payment Plan")
351
+ plan = st.session_state.payment_plan['payment_plan']
352
+ st.markdown(f"**Monthly Payment:** ${plan['monthly_payment']}")
353
+ st.markdown(f"**Duration:** {plan['duration_months']} months")
354
+ st.markdown(f"**First Payment Due:** {plan['due_date']}")
355
+
356
+ st.markdown("#### Negotiation Strategy:")
357
+ st.markdown(f"{st.session_state.payment_plan['negotiation_strategy']}")
358
+ st.markdown("</div>", unsafe_allow_html=True)
359
+
360
+ else:
361
+ st.info("👈 Please select a debtor from the sidebar to get started.")
362
+
363
+ # Footer
364
+ st.markdown("<hr>", unsafe_allow_html=True)
365
+ st.markdown("<p style='text-align: center; color: #6B7280;'>© 2025 Debt Collection AI System</p>", unsafe_allow_html=True)