Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -3,316 +3,260 @@ import gspread
|
|
3 |
from google.oauth2.service_account import Credentials
|
4 |
import os
|
5 |
import json
|
6 |
-
from
|
7 |
-
import math
|
8 |
|
9 |
conf1 = os.getenv('CONF')
|
10 |
dict = json.loads(conf1)
|
|
|
11 |
SHEET_ID = os.getenv('SHEET_ID')
|
12 |
|
13 |
SCOPES = ['https://www.googleapis.com/auth/spreadsheets', 'https://www.googleapis.com/auth/drive']
|
14 |
|
|
|
|
|
|
|
|
|
15 |
# Initialize Google Sheets client
|
16 |
creds = Credentials.from_service_account_info(dict, scopes=SCOPES)
|
17 |
gc = gspread.authorize(creds)
|
18 |
sheet = gc.open_by_key(SHEET_ID)
|
19 |
|
20 |
-
#
|
21 |
-
|
22 |
-
page_states = {}
|
23 |
|
24 |
-
|
25 |
-
|
26 |
-
try:
|
27 |
-
# Calculate recency score
|
28 |
-
last_meeting_date = datetime.strptime(latest_meeting, '%Y-%m-%d')
|
29 |
-
days_since = (datetime.now() - last_meeting_date).days
|
30 |
-
|
31 |
-
# If meeting was within last 5 days, give low priority (they were just visited)
|
32 |
-
if days_since < 5:
|
33 |
-
recency_score = 1
|
34 |
-
# For sleeping customers (no contact in 3+ months), give higher priority
|
35 |
-
elif days_since > 30:
|
36 |
-
recency_score = 5 # High priority to wake them up
|
37 |
-
else:
|
38 |
-
# Normal recency scoring for others
|
39 |
-
recency_score = 5 - min(4, math.floor(days_since / 30)) # 0-4 months scale
|
40 |
-
except:
|
41 |
-
recency_score = 1
|
42 |
-
|
43 |
-
# Calculate frequency score (1 visit = 5 calls)
|
44 |
-
visit_equivalent = int(visit_times) * 5 if visit_times else 0
|
45 |
-
call_equivalent = int(call_times) if call_times else 0
|
46 |
-
total_interactions = visit_equivalent + call_equivalent
|
47 |
-
|
48 |
-
# Base frequency score
|
49 |
-
frequency_score = min(5, math.ceil(total_interactions / 5)) # Every 5 interactions = 1 point, max 5
|
50 |
-
|
51 |
-
# Bonus for consistent interaction (high number of total interactions)
|
52 |
-
if total_interactions > 20: # Indicates a close partner
|
53 |
-
frequency_score = min(5, frequency_score + 1) # Bonus point for long-term relationship
|
54 |
-
|
55 |
-
# Monetary score is directly input by user (1-5 scale)
|
56 |
-
monetary_score = min(5, max(1, int(monetary_value))) if monetary_value else 1
|
57 |
-
|
58 |
-
# Calculate total RFM score with adjusted weights
|
59 |
-
# More weight on recency for sleeping customers and monetary value for close partners
|
60 |
-
if days_since > 30: # Sleeping customer
|
61 |
-
total_score = (recency_score * 0.4 + frequency_score * 0.3 + monetary_score * 0.3) * 20
|
62 |
-
elif total_interactions > 20: # Close partner
|
63 |
-
total_score = (recency_score * 0.3 + frequency_score * 0.4 + monetary_score * 0.3) * 20
|
64 |
-
else: # Normal customer
|
65 |
-
total_score = (recency_score * 0.35 + frequency_score * 0.35 + monetary_score * 0.3) * 20
|
66 |
-
|
67 |
-
return round(total_score)
|
68 |
|
69 |
def verify_username(username):
|
70 |
"""Verify if username exists in user form"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
71 |
try:
|
72 |
user_sheet = sheet.worksheet('Users')
|
73 |
usernames = user_sheet.col_values(2) # Assuming username is in column B
|
74 |
is_valid = username in usernames
|
75 |
|
|
|
76 |
if is_valid:
|
77 |
-
|
78 |
-
|
79 |
-
page_states[username] = 1 # Start at page 1
|
80 |
-
|
81 |
return {
|
|
|
82 |
customer_section: gr.update(visible=is_valid),
|
83 |
-
update_section: gr.update(visible=is_valid)
|
84 |
-
search_section: gr.update(visible=is_valid),
|
85 |
-
username_display: gr.update(value=f"Logged in as: {username}" if is_valid else "")
|
86 |
}
|
87 |
except Exception as e:
|
88 |
return {
|
|
|
89 |
customer_section: gr.update(visible=False),
|
90 |
-
update_section: gr.update(visible=False)
|
91 |
-
search_section: gr.update(visible=False),
|
92 |
-
username_display: gr.update(value=f"Error: {str(e)}")
|
93 |
}
|
94 |
|
95 |
-
def
|
96 |
-
"""Get customers
|
97 |
-
if
|
98 |
return "Please verify your username first"
|
99 |
-
|
100 |
-
try:
|
101 |
-
# Get current page number and increment it
|
102 |
-
current_page = page_states.get(username, 1)
|
103 |
-
page_states[username] = current_page + 1
|
104 |
-
|
105 |
-
customer_sheet = sheet.worksheet('Customers')
|
106 |
-
all_records = customer_sheet.get_all_records()
|
107 |
-
|
108 |
-
# Filter records for current user
|
109 |
-
user_records = [r for r in all_records if r.get('username') == username]
|
110 |
-
|
111 |
-
# Calculate RFM scores for all customers
|
112 |
-
for record in user_records:
|
113 |
-
record['rfm_score'] = calculate_rfm_score(
|
114 |
-
record.get('latest_meeting_date', ''),
|
115 |
-
record.get('visit_times', 0),
|
116 |
-
record.get('call_times', 0),
|
117 |
-
record.get('monetary_value', 1)
|
118 |
-
)
|
119 |
-
|
120 |
-
if not user_records:
|
121 |
-
return "No customers found for your account"
|
122 |
-
|
123 |
-
# Sort by RFM score
|
124 |
-
sorted_customers = sorted(user_records, key=lambda x: x['rfm_score'], reverse=True)
|
125 |
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
Phone: {
|
142 |
-
Company: {
|
143 |
-
Name: {
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
------------------------\n"""
|
153 |
-
|
154 |
-
return result
|
155 |
except Exception as e:
|
156 |
return f"Error: {str(e)}"
|
157 |
|
158 |
-
def
|
159 |
-
"""Get
|
160 |
-
if
|
161 |
return "Please verify your username first"
|
162 |
-
|
163 |
try:
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
Name: {customer.get('Name', 'N/A')}
|
191 |
-
RFM Score: {customer.get('rfm_score', 0)}
|
192 |
-
Call Times: {customer.get('call_times', 0)}
|
193 |
-
Visit Times: {customer.get('visit_times', 0)}
|
194 |
-
Latest Meeting: {customer.get('latest_meeting_date', 'N/A')}
|
195 |
-
Monetary Value (1-5): {customer.get('monetary_value', 1)}
|
196 |
-
Country: {customer.get('Country', 'N/A')}
|
197 |
-
Products: {customer.get('Products', 'N/A')}
|
198 |
-
Remarks: {customer.get('Remark', 'N/A')}
|
199 |
-
------------------------\n"""
|
200 |
-
|
201 |
-
return result
|
202 |
except Exception as e:
|
203 |
return f"Error: {str(e)}"
|
204 |
|
205 |
-
def
|
206 |
-
"""Search for a customer by
|
207 |
-
if
|
208 |
return "Please verify your username first"
|
209 |
|
210 |
-
if not
|
211 |
-
return "Please enter a
|
212 |
|
213 |
try:
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
223 |
|
224 |
-
# Format results
|
225 |
-
result = "Search Results:\n\n"
|
226 |
-
for customer in matches:
|
227 |
-
rfm_score = calculate_rfm_score(
|
228 |
-
customer.get('latest_meeting_date', ''),
|
229 |
-
customer.get('visit_times', 0),
|
230 |
-
customer.get('call_times', 0),
|
231 |
-
customer.get('monetary_value', 1)
|
232 |
-
)
|
233 |
-
result += f"""Phone: {customer.get('Phone', 'N/A')}
|
234 |
-
Company: {customer.get('Company', 'N/A')}
|
235 |
-
Name: {customer.get('Name', 'N/A')}
|
236 |
-
RFM Score: {rfm_score}
|
237 |
-
Call Times: {customer.get('call_times', 0)}
|
238 |
-
Visit Times: {customer.get('visit_times', 0)}
|
239 |
-
Latest Meeting: {customer.get('latest_meeting_date', 'N/A')}
|
240 |
-
Monetary Value (1-5): {customer.get('monetary_value', 1)}
|
241 |
-
Country: {customer.get('Country', 'N/A')}
|
242 |
-
Products: {customer.get('Products', 'N/A')}
|
243 |
-
Remarks: {customer.get('Remark', 'N/A')}
|
244 |
-
------------------------\n"""
|
245 |
-
|
246 |
-
return result
|
247 |
except Exception as e:
|
248 |
return f"Error: {str(e)}"
|
249 |
|
250 |
-
def
|
251 |
-
|
252 |
-
"""Update customer information"""
|
253 |
-
if username not in active_users:
|
254 |
-
return "Please verify your username first"
|
255 |
-
|
256 |
-
if not selected_company:
|
257 |
-
return "Please select a company first"
|
258 |
-
|
259 |
try:
|
|
|
|
|
|
|
260 |
customer_sheet = sheet.worksheet('Customers')
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
if not customer_row:
|
274 |
-
return "Company not found in your records"
|
275 |
-
|
276 |
-
# Only update fields that have new values
|
277 |
-
updates = []
|
278 |
-
if call_times:
|
279 |
-
updates.append(('call_times', call_times, 5))
|
280 |
-
if visit_times:
|
281 |
-
updates.append(('visit_times', visit_times, 6))
|
282 |
-
if latest_meeting:
|
283 |
-
updates.append(('latest_meeting_date', latest_meeting, 7))
|
284 |
-
if monetary_value:
|
285 |
-
updates.append(('monetary_value', monetary_value, 8))
|
286 |
-
if country:
|
287 |
-
updates.append(('Country', country, 9))
|
288 |
-
if products:
|
289 |
-
updates.append(('Products', products, 10))
|
290 |
-
if remarks:
|
291 |
-
updates.append(('Remark', remarks, 11))
|
292 |
-
|
293 |
-
# Calculate new RFM score using new or existing values
|
294 |
-
rfm_score = calculate_rfm_score(
|
295 |
-
latest_meeting or customer_data.get('latest_meeting_date', ''),
|
296 |
-
visit_times or customer_data.get('visit_times', 0),
|
297 |
-
call_times or customer_data.get('call_times', 0),
|
298 |
-
monetary_value or customer_data.get('monetary_value', 1)
|
299 |
-
)
|
300 |
-
updates.append(('rfm_score', rfm_score, 12))
|
301 |
-
|
302 |
-
# Update only changed fields
|
303 |
-
for field, value, col in updates:
|
304 |
-
customer_sheet.update_cell(customer_row, col, value)
|
305 |
-
|
306 |
-
return f"Successfully updated customer information. New RFM score: {rfm_score}"
|
307 |
except Exception as e:
|
308 |
return f"Error: {str(e)}"
|
309 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
310 |
# Create Gradio interface
|
311 |
with gr.Blocks() as app:
|
312 |
gr.Markdown(
|
313 |
"""
|
314 |
-
# Customer Management System
|
315 |
-
### Efficiently manage and
|
316 |
---
|
317 |
"""
|
318 |
)
|
@@ -320,120 +264,89 @@ with gr.Blocks() as app:
|
|
320 |
# User Verification Section
|
321 |
gr.Markdown("### 1. User Verification")
|
322 |
with gr.Group():
|
323 |
-
|
324 |
-
|
325 |
-
|
|
|
|
|
|
|
|
|
|
|
326 |
|
327 |
# Customer Information Section
|
328 |
with gr.Group(visible=False) as customer_section:
|
329 |
-
gr.Markdown("### 2.
|
|
|
|
|
|
|
|
|
|
|
330 |
with gr.Row():
|
331 |
-
get_button = gr.Button("Get
|
332 |
-
show_all_button = gr.Button("Show All Customers", variant="secondary")
|
333 |
customer_info = gr.Textbox(
|
334 |
label="Customer Details",
|
335 |
interactive=False,
|
336 |
-
lines=
|
337 |
)
|
338 |
|
339 |
-
|
340 |
-
with gr.Group(visible=False) as search_section:
|
341 |
-
gr.Markdown("### 3. Search Customer")
|
342 |
-
search_input = gr.Textbox(label="Company Name", placeholder="Enter company name to search")
|
343 |
-
search_button = gr.Button("Search", variant="primary")
|
344 |
-
search_results = gr.Textbox(
|
345 |
-
label="Search Results",
|
346 |
-
interactive=False,
|
347 |
-
lines=12
|
348 |
-
)
|
349 |
|
350 |
-
# Update Section
|
351 |
with gr.Group(visible=False) as update_section:
|
352 |
-
gr.Markdown("###
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
monetary_input = gr.Slider(
|
365 |
-
label="Monetary Value (1-5)",
|
366 |
-
minimum=1,
|
367 |
-
maximum=5,
|
368 |
-
step=1
|
369 |
-
)
|
370 |
-
country_input = gr.Textbox(label="Country")
|
371 |
-
products_input = gr.Textbox(label="Products")
|
372 |
-
remarks_input = gr.Textbox(label="Remarks", lines=3)
|
373 |
-
|
374 |
-
update_button = gr.Button("Update Customer", variant="primary")
|
375 |
-
update_status = gr.Textbox(label="Update Status", interactive=False)
|
376 |
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
try:
|
381 |
-
customer_sheet = sheet.worksheet('Customers')
|
382 |
-
all_records = customer_sheet.get_all_records()
|
383 |
-
matches = [r['Company'] for r in all_records
|
384 |
-
if search_text.lower() in r['Company'].lower()
|
385 |
-
and r.get('username') == username]
|
386 |
-
return gr.update(choices=matches)
|
387 |
-
except Exception:
|
388 |
-
return gr.update(choices=[])
|
389 |
|
390 |
# Event handlers
|
391 |
verify_button.click(
|
392 |
fn=verify_username,
|
393 |
inputs=username_input,
|
394 |
-
outputs=[customer_section, update_section
|
395 |
)
|
396 |
|
397 |
get_button.click(
|
398 |
-
fn=
|
399 |
inputs=username_input,
|
400 |
outputs=customer_info
|
401 |
)
|
402 |
-
|
403 |
show_all_button.click(
|
404 |
fn=get_all_customers,
|
405 |
inputs=username_input,
|
406 |
outputs=customer_info
|
407 |
)
|
408 |
-
|
409 |
search_button.click(
|
410 |
-
fn=
|
411 |
-
inputs=[username_input,
|
412 |
-
outputs=
|
413 |
-
)
|
414 |
-
|
415 |
-
# Update company dropdown when searching
|
416 |
-
search_input.change(
|
417 |
-
fn=update_company_choices,
|
418 |
-
inputs=[username_input, search_input],
|
419 |
-
outputs=selected_company
|
420 |
)
|
421 |
|
422 |
-
|
423 |
-
fn=
|
424 |
inputs=[
|
425 |
username_input,
|
426 |
-
|
427 |
-
call_times_input,
|
428 |
-
visit_times_input,
|
429 |
-
latest_meeting_input,
|
430 |
-
monetary_input,
|
431 |
country_input,
|
432 |
products_input,
|
433 |
-
|
434 |
],
|
435 |
-
outputs=
|
436 |
)
|
437 |
|
438 |
-
# Launch the app
|
439 |
app.launch()
|
|
|
3 |
from google.oauth2.service_account import Credentials
|
4 |
import os
|
5 |
import json
|
6 |
+
from threading import Lock
|
|
|
7 |
|
8 |
conf1 = os.getenv('CONF')
|
9 |
dict = json.loads(conf1)
|
10 |
+
# Google Sheets settings
|
11 |
SHEET_ID = os.getenv('SHEET_ID')
|
12 |
|
13 |
SCOPES = ['https://www.googleapis.com/auth/spreadsheets', 'https://www.googleapis.com/auth/drive']
|
14 |
|
15 |
+
# Gradio login credentials
|
16 |
+
log = os.getenv('LOGIN')
|
17 |
+
password = os.getenv('PASSWORD')
|
18 |
+
|
19 |
# Initialize Google Sheets client
|
20 |
creds = Credentials.from_service_account_info(dict, scopes=SCOPES)
|
21 |
gc = gspread.authorize(creds)
|
22 |
sheet = gc.open_by_key(SHEET_ID)
|
23 |
|
24 |
+
# Create a lock for synchronizing sheet access
|
25 |
+
sheet_lock = Lock()
|
|
|
26 |
|
27 |
+
# Dictionary to store customer info per user session
|
28 |
+
user_customers = {}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
|
30 |
def verify_username(username):
|
31 |
"""Verify if username exists in user form"""
|
32 |
+
telescripts = '''Hello, this is (your name ) from CEV auto, a professional car export company.
|
33 |
+
|
34 |
+
the reason i called you today is to introduce you to our services if you have a minute?
|
35 |
+
|
36 |
+
as i told you we are a professional car export company,We have built a platform that specifically helps businesses source vehicles from China and streamline the entire purchasing and export process.
|
37 |
+
|
38 |
+
Have you purchased Chinese vehicles before? If so, which brands or models?
|
39 |
+
("If not: "Many companies like yours are now exploring Chinese vehicles for their competitiveness and affordability.")
|
40 |
+
To better understand your business, could you tell me which country you're based in and the types of products your company focuses on?"
|
41 |
+
|
42 |
+
(if they are not in the car business you say:) think about it, its an untapped market, where few people get to make a lot of money out of it, however this business is getting popular,for us we are not looking for just clients, we are looking for potential partners who can join us to make a movement.
|
43 |
+
lets arrange a time we meet and get to know each other more, and you get to know more about our business and team. i will add you on wechat to fix a time.
|
44 |
+
|
45 |
+
--------------------------------------------------------------------------------------------------------
|
46 |
+
|
47 |
+
why we call: two reasons:
|
48 |
+
1-to get the client to come to our office to buy.
|
49 |
+
2-to get informations about them ( country, what products do they sell)
|
50 |
+
--------------------------------------------------------------------------------------------------------
|
51 |
+
|
52 |
+
Introduction:
|
53 |
+
"Hello [Customer's Name], this is [Your Name] from CEVauto, your trusted partner in automotive exports. How are you doing today?"
|
54 |
+
|
55 |
+
Acknowledge Previous Contact:
|
56 |
+
"I'm reaching out because we noticed you've shown interest in our services before, and we truly appreciate your consideration of CEVauto for your automotive needs."
|
57 |
+
|
58 |
+
Value Proposition:
|
59 |
+
"We wanted to let you know about some exciting updates that could benefit your business. At CEVauto, we've been working hard to enhance our offerings, and now we're proud to provide even more competitive pricing and more stable delivery timelines than ever before."
|
60 |
+
|
61 |
+
Benefits:
|
62 |
+
"By choosing CEVauto, you can expect:
|
63 |
+
|
64 |
+
Cost-effective solutions that maximize your budget.
|
65 |
+
|
66 |
+
Reliable delivery schedules to keep your operations running smoothly.
|
67 |
+
|
68 |
+
A wide range of high-quality vehicles to meet your specific requirements."
|
69 |
+
|
70 |
+
Call to Action:
|
71 |
+
"We believe these improvements can make a significant difference for your business. Could we schedule a brief call to discuss how we can tailor our services to meet your current needs?"
|
72 |
+
|
73 |
+
Closing:
|
74 |
+
"Thank you for considering CEVauto once again. We're here to support your success and look forward to the opportunity to work with you. Please feel free to reach out at any time. Have a great day!"
|
75 |
+
|
76 |
+
'''
|
77 |
try:
|
78 |
user_sheet = sheet.worksheet('Users')
|
79 |
usernames = user_sheet.col_values(2) # Assuming username is in column B
|
80 |
is_valid = username in usernames
|
81 |
|
82 |
+
# Initialize user's customer tracking if valid
|
83 |
if is_valid:
|
84 |
+
user_customers[username] = None
|
85 |
+
|
|
|
|
|
86 |
return {
|
87 |
+
verify_output: telescripts if is_valid else "Invalid username",
|
88 |
customer_section: gr.update(visible=is_valid),
|
89 |
+
update_section: gr.update(visible=is_valid)
|
|
|
|
|
90 |
}
|
91 |
except Exception as e:
|
92 |
return {
|
93 |
+
verify_output: f"Error: {str(e)}",
|
94 |
customer_section: gr.update(visible=False),
|
95 |
+
update_section: gr.update(visible=False)
|
|
|
|
|
96 |
}
|
97 |
|
98 |
+
def get_all_customers(username):
|
99 |
+
"""Get all customers assigned to the username"""
|
100 |
+
if not username:
|
101 |
return "Please verify your username first"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
102 |
|
103 |
+
try:
|
104 |
+
with sheet_lock:
|
105 |
+
customer_sheet = sheet.worksheet('Customers')
|
106 |
+
all_records = customer_sheet.get_all_records()
|
107 |
+
|
108 |
+
# Filter records where username matches
|
109 |
+
user_records = [record for record in all_records if record.get('username') == username]
|
110 |
+
|
111 |
+
if not user_records:
|
112 |
+
return "No customers found for your username"
|
113 |
+
|
114 |
+
# Format all customer records
|
115 |
+
result = "Your Customers:\n\n"
|
116 |
+
for record in user_records:
|
117 |
+
result += f"""
|
118 |
+
Phone: {record['Phone']}
|
119 |
+
Company: {record['Company']}
|
120 |
+
Name: {record['Name']}
|
121 |
+
Status: {record.get('status', '')}
|
122 |
+
Country: {record.get('Country', '')}
|
123 |
+
Products: {record.get('Products', '')}
|
124 |
+
Remark: {record.get('Remark', '')}
|
125 |
+
------------------------
|
126 |
+
"""
|
127 |
+
return result
|
128 |
+
|
|
|
|
|
|
|
129 |
except Exception as e:
|
130 |
return f"Error: {str(e)}"
|
131 |
|
132 |
+
def get_customer_info(username):
|
133 |
+
"""Get and display customer information, update get column"""
|
134 |
+
if not username:
|
135 |
return "Please verify your username first"
|
136 |
+
|
137 |
try:
|
138 |
+
with sheet_lock:
|
139 |
+
customer_sheet = sheet.worksheet('Customers')
|
140 |
+
all_records = customer_sheet.get_all_records()
|
141 |
+
|
142 |
+
# Find first row where 'get' is empty
|
143 |
+
for idx, record in enumerate(all_records):
|
144 |
+
if not record['get']:
|
145 |
+
# Update 'get' column to 'yes'
|
146 |
+
customer_sheet.update_cell(idx + 2, 4, 'yes') # +2 for header row and 1-based index
|
147 |
+
|
148 |
+
# Store customer info for this user session
|
149 |
+
user_customers[username] = {
|
150 |
+
'row': idx + 2,
|
151 |
+
'Phone': record['Phone'],
|
152 |
+
'Company': record['Company'],
|
153 |
+
'Name': record['Name']
|
154 |
+
}
|
155 |
+
|
156 |
+
# Return customer information
|
157 |
+
return f"""
|
158 |
+
Phone: {record['Phone']}
|
159 |
+
Company: {record['Company']}
|
160 |
+
Name: {record['Name']}
|
161 |
+
"""
|
162 |
+
|
163 |
+
return "No available customer records found"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
164 |
except Exception as e:
|
165 |
return f"Error: {str(e)}"
|
166 |
|
167 |
+
def search_customer_by_phone(username, phone):
|
168 |
+
"""Search for a customer by phone number and assign to current user"""
|
169 |
+
if not username:
|
170 |
return "Please verify your username first"
|
171 |
|
172 |
+
if not phone:
|
173 |
+
return "Please enter a phone number"
|
174 |
|
175 |
try:
|
176 |
+
with sheet_lock:
|
177 |
+
customer_sheet = sheet.worksheet('Customers')
|
178 |
+
all_records = customer_sheet.get_all_records()
|
179 |
+
|
180 |
+
# Find customer by phone number
|
181 |
+
for idx, record in enumerate(all_records):
|
182 |
+
if str(record['Phone']) == str(phone):
|
183 |
+
# Store customer info for this user session
|
184 |
+
user_customers[username] = {
|
185 |
+
'row': idx + 2, # +2 for header row and 1-based index
|
186 |
+
'Phone': record['Phone'],
|
187 |
+
'Company': record['Company'],
|
188 |
+
'Name': record['Name']
|
189 |
+
}
|
190 |
+
|
191 |
+
return f"""
|
192 |
+
Phone: {record['Phone']}
|
193 |
+
Company: {record['Company']}
|
194 |
+
Name: {record['Name']}
|
195 |
+
Status: {record.get('status', '')}
|
196 |
+
Country: {record.get('Country', '')}
|
197 |
+
Products: {record.get('Products', '')}
|
198 |
+
Remark: {record.get('Remark', '')}
|
199 |
+
"""
|
200 |
+
|
201 |
+
return "No customer found with this phone number"
|
202 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
203 |
except Exception as e:
|
204 |
return f"Error: {str(e)}"
|
205 |
|
206 |
+
def get_current_customer_info(username):
|
207 |
+
"""Get the current customer's information"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
208 |
try:
|
209 |
+
if username not in user_customers or user_customers[username] is None:
|
210 |
+
return "No current customer selected"
|
211 |
+
|
212 |
customer_sheet = sheet.worksheet('Customers')
|
213 |
+
row_values = customer_sheet.row_values(user_customers[username]['row'])
|
214 |
+
|
215 |
+
return f"""
|
216 |
+
Phone: {row_values[0]}
|
217 |
+
Company: {row_values[1]}
|
218 |
+
Name: {row_values[2]}
|
219 |
+
Status: {row_values[5] if len(row_values) > 5 else ''}
|
220 |
+
Country: {row_values[6] if len(row_values) > 6 else ''}
|
221 |
+
Products: {row_values[7] if len(row_values) > 7 else ''}
|
222 |
+
Remark: {row_values[8] if len(row_values) > 8 else ''}
|
223 |
+
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
224 |
except Exception as e:
|
225 |
return f"Error: {str(e)}"
|
226 |
|
227 |
+
def submit_customer_update(username, status, country, products, remark):
|
228 |
+
"""Submit customer information updates and refresh display"""
|
229 |
+
if username not in user_customers or user_customers[username] is None:
|
230 |
+
return "No customer selected", "Please get a customer first"
|
231 |
+
|
232 |
+
try:
|
233 |
+
with sheet_lock:
|
234 |
+
customer_sheet = sheet.worksheet('Customers')
|
235 |
+
|
236 |
+
# Update the fields in the correct row
|
237 |
+
updates = [
|
238 |
+
('username', username, 5), # Column E
|
239 |
+
('status', status, 6), # Column F
|
240 |
+
('Country', country, 7), # Column G
|
241 |
+
('Products', products, 8), # Column H
|
242 |
+
('Remark', remark, 9) # Column I
|
243 |
+
]
|
244 |
+
|
245 |
+
for field, value, col in updates:
|
246 |
+
customer_sheet.update_cell(user_customers[username]['row'], col, value)
|
247 |
+
|
248 |
+
# Get updated customer information
|
249 |
+
updated_info = get_current_customer_info(username)
|
250 |
+
return "Update successful", updated_info
|
251 |
+
except Exception as e:
|
252 |
+
return f"Error: {str(e)}", "Error occurred while updating"
|
253 |
+
|
254 |
# Create Gradio interface
|
255 |
with gr.Blocks() as app:
|
256 |
gr.Markdown(
|
257 |
"""
|
258 |
+
# CEVauto Customer Management System
|
259 |
+
### Efficiently manage and update customer information
|
260 |
---
|
261 |
"""
|
262 |
)
|
|
|
264 |
# User Verification Section
|
265 |
gr.Markdown("### 1. User Verification")
|
266 |
with gr.Group():
|
267 |
+
with gr.Row():
|
268 |
+
with gr.Column(scale=3):
|
269 |
+
username_input = gr.Textbox(label="Username", placeholder="Enter your username")
|
270 |
+
with gr.Column(scale=1):
|
271 |
+
verify_button = gr.Button("Verify", variant="primary")
|
272 |
+
verify_output = gr.Textbox(label="Cold Call Scripts", interactive=False)
|
273 |
+
|
274 |
+
gr.Markdown("---")
|
275 |
|
276 |
# Customer Information Section
|
277 |
with gr.Group(visible=False) as customer_section:
|
278 |
+
gr.Markdown("### 2. Customer Information")
|
279 |
+
with gr.Row():
|
280 |
+
with gr.Column(scale=2):
|
281 |
+
phone_search = gr.Textbox(label="Search by Phone", placeholder="Enter phone number")
|
282 |
+
with gr.Column(scale=1):
|
283 |
+
search_button = gr.Button("Search Customer", variant="secondary")
|
284 |
with gr.Row():
|
285 |
+
get_button = gr.Button("Get Next Customer", variant="primary")
|
286 |
+
show_all_button = gr.Button("Show All My Customers", variant="secondary")
|
287 |
customer_info = gr.Textbox(
|
288 |
label="Customer Details",
|
289 |
interactive=False,
|
290 |
+
lines=15
|
291 |
)
|
292 |
|
293 |
+
gr.Markdown("---")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
294 |
|
295 |
+
# Update Status Section
|
296 |
with gr.Group(visible=False) as update_section:
|
297 |
+
gr.Markdown("### 3. Update Customer Status")
|
298 |
+
with gr.Row():
|
299 |
+
with gr.Column():
|
300 |
+
status_input = gr.Dropdown(
|
301 |
+
choices=["Unconnected", "Invalid", "Not interested", "interested", "Willing"],
|
302 |
+
label="Status",
|
303 |
+
value="Unconnected"
|
304 |
+
)
|
305 |
+
country_input = gr.Textbox(label="Country", placeholder="Enter customer's country")
|
306 |
+
with gr.Column():
|
307 |
+
products_input = gr.Textbox(label="Products", placeholder="Enter relevant products")
|
308 |
+
remark_input = gr.Textbox(label="Remark", placeholder="Add any additional notes", lines=2)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
309 |
|
310 |
+
with gr.Row():
|
311 |
+
submit_button = gr.Button("Submit Update", variant="primary")
|
312 |
+
submit_output = gr.Textbox(label="Update Status", interactive=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
313 |
|
314 |
# Event handlers
|
315 |
verify_button.click(
|
316 |
fn=verify_username,
|
317 |
inputs=username_input,
|
318 |
+
outputs=[verify_output, customer_section, update_section]
|
319 |
)
|
320 |
|
321 |
get_button.click(
|
322 |
+
fn=get_customer_info,
|
323 |
inputs=username_input,
|
324 |
outputs=customer_info
|
325 |
)
|
326 |
+
|
327 |
show_all_button.click(
|
328 |
fn=get_all_customers,
|
329 |
inputs=username_input,
|
330 |
outputs=customer_info
|
331 |
)
|
332 |
+
|
333 |
search_button.click(
|
334 |
+
fn=search_customer_by_phone,
|
335 |
+
inputs=[username_input, phone_search],
|
336 |
+
outputs=customer_info
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
337 |
)
|
338 |
|
339 |
+
submit_button.click(
|
340 |
+
fn=submit_customer_update,
|
341 |
inputs=[
|
342 |
username_input,
|
343 |
+
status_input,
|
|
|
|
|
|
|
|
|
344 |
country_input,
|
345 |
products_input,
|
346 |
+
remark_input
|
347 |
],
|
348 |
+
outputs=[submit_output, customer_info]
|
349 |
)
|
350 |
|
351 |
+
# Launch the app with authentication
|
352 |
app.launch()
|