JayBene1 commited on
Commit
14348e1
·
verified ·
1 Parent(s): c329cb0

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +818 -0
app.py ADDED
@@ -0,0 +1,818 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import requests
3
+ import re
4
+ import json
5
+ import csv
6
+ import io
7
+ from urllib.parse import urlparse, urljoin
8
+ import time
9
+ import random
10
+
11
+ # Mock contacts database (same as your API)
12
+ CONTACTS_DB = [
13
+ {
14
+ "id": 1,
15
+ "first_name": "Sarah",
16
+ "last_name": "Chen",
17
+ "email": "sarah.chen@techflowsolutions.com",
18
+ "phone": "+1-555-0101",
19
+ "job_title": "CTO",
20
+ "company": "TechFlow Solutions",
21
+ "website": "https://techflowsolutions.com"
22
+ },
23
+ {
24
+ "id": 2,
25
+ "first_name": "Marcus",
26
+ "last_name": "Rodriguez",
27
+ "email": "m.rodriguez@techflowsolutions.com",
28
+ "phone": "+1-555-0102",
29
+ "job_title": "Senior Developer",
30
+ "company": "TechFlow Solutions",
31
+ "website": "https://techflowsolutions.com"
32
+ },
33
+ {
34
+ "id": 3,
35
+ "first_name": "Emma",
36
+ "last_name": "Thompson",
37
+ "email": "emma@greenleafconsult.com",
38
+ "phone": "+1-555-0201",
39
+ "job_title": "Managing Partner",
40
+ "company": "GreenLeaf Consulting",
41
+ "website": "https://greenleafconsult.com"
42
+ },
43
+ {
44
+ "id": 4,
45
+ "first_name": "David",
46
+ "last_name": "Park",
47
+ "email": "david.park@greenleafconsult.com",
48
+ "phone": "+1-555-0202",
49
+ "job_title": "Environmental Analyst",
50
+ "company": "GreenLeaf Consulting",
51
+ "website": "https://greenleafconsult.com"
52
+ },
53
+ {
54
+ "id": 5,
55
+ "first_name": "Jessica",
56
+ "last_name": "Williams",
57
+ "email": "jessica@blueskymarketing.net",
58
+ "phone": "+1-555-0301",
59
+ "job_title": "Creative Director",
60
+ "company": "BlueSky Marketing",
61
+ "website": "https://blueskymarketing.net"
62
+ },
63
+ {
64
+ "id": 6,
65
+ "first_name": "Ryan",
66
+ "last_name": "Mitchell",
67
+ "email": "ryan.mitchell@blueskymarketing.net",
68
+ "phone": "+1-555-0302",
69
+ "job_title": "Account Manager",
70
+ "company": "BlueSky Marketing",
71
+ "website": "https://blueskymarketing.net"
72
+ },
73
+ {
74
+ "id": 7,
75
+ "first_name": "Lisa",
76
+ "last_name": "Zhang",
77
+ "email": "l.zhang@quantumdynamics.org",
78
+ "phone": "+1-555-0401",
79
+ "job_title": "Research Director",
80
+ "company": "Quantum Dynamics Corp",
81
+ "website": "https://quantumdynamics.org"
82
+ },
83
+ {
84
+ "id": 8,
85
+ "first_name": "Ahmed",
86
+ "last_name": "Hassan",
87
+ "email": "ahmed.hassan@quantumdynamics.org",
88
+ "phone": "+1-555-0402",
89
+ "job_title": "Quantum Engineer",
90
+ "company": "Quantum Dynamics Corp",
91
+ "website": "https://quantumdynamics.org"
92
+ },
93
+ {
94
+ "id": 9,
95
+ "first_name": "Maria",
96
+ "last_name": "Gonzalez",
97
+ "email": "maria@stellarlogistics.biz",
98
+ "phone": "+1-555-0501",
99
+ "job_title": "Operations Manager",
100
+ "company": "Stellar Logistics",
101
+ "website": "https://stellarlogistics.biz"
102
+ },
103
+ {
104
+ "id": 10,
105
+ "first_name": "James",
106
+ "last_name": "O'Connor",
107
+ "email": "james.oconnor@stellarlogistics.biz",
108
+ "phone": "+1-555-0502",
109
+ "job_title": "Fleet Coordinator",
110
+ "company": "Stellar Logistics",
111
+ "website": "https://stellarlogistics.biz"
112
+ },
113
+ {
114
+ "id": 11,
115
+ "first_name": "Robert",
116
+ "last_name": "Kim",
117
+ "email": "robert.kim@nexusfinancial.pro",
118
+ "phone": "+1-555-0601",
119
+ "job_title": "Senior Advisor",
120
+ "company": "Nexus Financial",
121
+ "website": "https://nexusfinancial.pro"
122
+ },
123
+ {
124
+ "id": 12,
125
+ "first_name": "Catherine",
126
+ "last_name": "Lee",
127
+ "email": "catherine@nexusfinancial.pro",
128
+ "phone": "+1-555-0602",
129
+ "job_title": "Investment Analyst",
130
+ "company": "Nexus Financial",
131
+ "website": "https://nexusfinancial.pro"
132
+ },
133
+ {
134
+ "id": 13,
135
+ "first_name": "Michael",
136
+ "last_name": "Johnson",
137
+ "email": "m.johnson@horizonhealth.care",
138
+ "phone": "+1-555-0701",
139
+ "job_title": "Chief Medical Officer",
140
+ "company": "Horizon Health Systems",
141
+ "website": "https://horizonhealth.care"
142
+ },
143
+ {
144
+ "id": 14,
145
+ "first_name": "Jennifer",
146
+ "last_name": "Adams",
147
+ "email": "jennifer.adams@horizonhealth.care",
148
+ "phone": "+1-555-0702",
149
+ "job_title": "Head Nurse",
150
+ "company": "Horizon Health Systems",
151
+ "website": "https://horizonhealth.care"
152
+ },
153
+ {
154
+ "id": 15,
155
+ "first_name": "Tony",
156
+ "last_name": "Ricci",
157
+ "email": "tony.ricci@phoenixmfg.com",
158
+ "phone": "+1-555-0801",
159
+ "job_title": "Plant Manager",
160
+ "company": "Phoenix Manufacturing",
161
+ "website": "https://phoenixmfg.com"
162
+ },
163
+ {
164
+ "id": 16,
165
+ "first_name": "Linda",
166
+ "last_name": "Martinez",
167
+ "email": "linda.martinez@phoenixmfg.com",
168
+ "phone": "+1-555-0802",
169
+ "job_title": "Quality Control Supervisor",
170
+ "company": "Phoenix Manufacturing",
171
+ "website": "https://phoenixmfg.com"
172
+ },
173
+ {
174
+ "id": 17,
175
+ "first_name": "Patricia",
176
+ "last_name": "White",
177
+ "email": "patricia.white@alpineeducation.edu",
178
+ "phone": "+1-555-0901",
179
+ "job_title": "Director of Programs",
180
+ "company": "Alpine Education Group",
181
+ "website": "https://alpineeducation.edu"
182
+ },
183
+ {
184
+ "id": 18,
185
+ "first_name": "Kevin",
186
+ "last_name": "Brown",
187
+ "email": "kevin.brown@alpineeducation.edu",
188
+ "phone": "+1-555-0902",
189
+ "job_title": "Curriculum Specialist",
190
+ "company": "Alpine Education Group",
191
+ "website": "https://alpineeducation.edu"
192
+ },
193
+ {
194
+ "id": 19,
195
+ "first_name": "Sophia",
196
+ "last_name": "Taylor",
197
+ "email": "sophia@crimsoncreative.studio",
198
+ "phone": "+1-555-1001",
199
+ "job_title": "Art Director",
200
+ "company": "Crimson Creative Studio",
201
+ "website": "https://crimsoncreative.studio"
202
+ },
203
+ {
204
+ "id": 20,
205
+ "first_name": "Alex",
206
+ "last_name": "Cooper",
207
+ "email": "alex.cooper@crimsoncreative.studio",
208
+ "phone": "+1-555-1002",
209
+ "job_title": "Graphic Designer",
210
+ "company": "Crimson Creative Studio",
211
+ "website": "https://crimsoncreative.studio"
212
+ }
213
+ ]
214
+
215
+ def extract_domain(url):
216
+ """Extract domain from URL"""
217
+ try:
218
+ if not url.startswith(('http://', 'https://')):
219
+ url = 'https://' + url
220
+ parsed = urlparse(url)
221
+ domain = parsed.netloc.lower()
222
+ # Remove www. if present
223
+ if domain.startswith('www.'):
224
+ domain = domain[4:]
225
+ return domain
226
+ except:
227
+ return ""
228
+
229
+ def find_contacts_by_website(website_url):
230
+ """Find contacts that match the website domain"""
231
+ target_domain = extract_domain(website_url)
232
+ if not target_domain:
233
+ return []
234
+
235
+ print(f"Searching for domain: {target_domain}") # Debug info
236
+
237
+ matching_contacts = []
238
+ for contact in CONTACTS_DB:
239
+ contact_domain = extract_domain(contact['website'])
240
+ print(f"Comparing with: {contact_domain}") # Debug info
241
+
242
+ # Exact domain match or subdomain match
243
+ if target_domain == contact_domain or target_domain in contact_domain or contact_domain in target_domain:
244
+ matching_contacts.append(contact)
245
+
246
+ print(f"Found {len(matching_contacts)} matching contacts") # Debug info
247
+ return matching_contacts
248
+
249
+ def simulate_website_scraping(url):
250
+ """Simulate scraping a website and finding contact information"""
251
+ # Add some delay to simulate real scraping
252
+ time.sleep(random.uniform(0.5, 1))
253
+
254
+ # Find matching contacts from our database
255
+ contacts = find_contacts_by_website(url)
256
+
257
+ return contacts
258
+
259
+ def is_valid_url(url):
260
+ """Check if a string looks like a valid URL"""
261
+ url = url.strip()
262
+ if not url:
263
+ return False
264
+
265
+ # Check if it contains common URL patterns
266
+ url_patterns = [
267
+ r'^\w+\.\w+', # domain.com
268
+ r'^\w+\.\w+\.\w+', # subdomain.domain.com
269
+ r'^https?://', # starts with http/https
270
+ r'www\.', # contains www
271
+ ]
272
+
273
+ for pattern in url_patterns:
274
+ if re.search(pattern, url.lower()):
275
+ return True
276
+
277
+ return False
278
+
279
+ def parse_csv_file(file_obj):
280
+ """Parse CSV file and extract website URLs from column H (or auto-detect)"""
281
+ websites = []
282
+ debug_info = []
283
+
284
+ try:
285
+ # Handle different file input types
286
+ if hasattr(file_obj, 'name'):
287
+ # This is a file path (NamedString from Gradio)
288
+ with open(file_obj.name, 'r', encoding='utf-8') as f:
289
+ content = f.read()
290
+ elif isinstance(file_obj, str):
291
+ # This is already a string
292
+ content = file_obj
293
+ else:
294
+ # This might be bytes
295
+ content = file_obj.decode('utf-8')
296
+
297
+ # Parse CSV
298
+ csv_reader = csv.reader(io.StringIO(content))
299
+ rows = list(csv_reader)
300
+
301
+ if not rows:
302
+ debug_info.append("CSV file is empty")
303
+ return [], debug_info
304
+
305
+ debug_info.append(f"Total rows in CSV: {len(rows)}")
306
+
307
+ # Analyze the first few rows to understand structure
308
+ if len(rows) > 0:
309
+ debug_info.append(f"First row has {len(rows[0])} columns: {rows[0]}")
310
+ if len(rows) > 1:
311
+ debug_info.append(f"Second row has {len(rows[1])} columns: {rows[1]}")
312
+
313
+ # Check if first row looks like headers
314
+ first_row = rows[0]
315
+ has_headers = any(col.lower() in ['website', 'url', 'domain', 'site', 'web'] for col in first_row)
316
+
317
+ # Try to find website column
318
+ website_column_index = None
319
+
320
+ # First, try column H (index 7)
321
+ if len(first_row) >= 8:
322
+ website_column_index = 7
323
+ debug_info.append(f"Using column H (index 7) as specified")
324
+ else:
325
+ # Auto-detect website column
326
+ for i, col in enumerate(first_row):
327
+ if col.lower() in ['website', 'url', 'domain', 'site', 'web']:
328
+ website_column_index = i
329
+ debug_info.append(f"Auto-detected website column at index {i}: '{col}'")
330
+ break
331
+
332
+ if website_column_index is None:
333
+ # If no obvious column found, scan all columns for URLs
334
+ debug_info.append("No obvious website column found, scanning all columns for URLs...")
335
+ for row_idx, row in enumerate(rows[1:] if has_headers else rows, start=1):
336
+ for col_idx, cell in enumerate(row):
337
+ if is_valid_url(cell):
338
+ website_column_index = col_idx
339
+ debug_info.append(f"Found URLs in column {col_idx} (row {row_idx}): '{cell}'")
340
+ break
341
+ if website_column_index is not None:
342
+ break
343
+
344
+ if website_column_index is None:
345
+ debug_info.append("ERROR: Could not find any column with website URLs")
346
+ return [], debug_info
347
+
348
+ # Extract websites from the identified column
349
+ start_row = 1 if has_headers else 0
350
+ for row_idx, row in enumerate(rows[start_row:], start=start_row + 1):
351
+ if len(row) > website_column_index:
352
+ website_url = row[website_column_index].strip()
353
+ if website_url and is_valid_url(website_url):
354
+ websites.append(website_url)
355
+ debug_info.append(f"Found website in row {row_idx}: {website_url}")
356
+ elif website_url:
357
+ debug_info.append(f"Row {row_idx}: '{website_url}' doesn't look like a valid URL")
358
+ else:
359
+ debug_info.append(f"Row {row_idx}: Empty cell in website column")
360
+ else:
361
+ debug_info.append(f"Row {row_idx}: Has only {len(row)} columns, need at least {website_column_index + 1}")
362
+
363
+ debug_info.append(f"Total websites extracted: {len(websites)}")
364
+ if websites:
365
+ debug_info.append(f"Sample websites: {websites[:5]}")
366
+
367
+ return websites, debug_info
368
+
369
+ except Exception as e:
370
+ debug_info.append(f"Error parsing CSV: {e}")
371
+ return [], debug_info
372
+
373
+ def search_csv_websites(csv_file, max_results=10):
374
+ """Search for contacts from websites listed in CSV file"""
375
+ if csv_file is None:
376
+ return "Please upload a CSV file", ""
377
+
378
+ try:
379
+ # Parse CSV file
380
+ websites, debug_info = parse_csv_file(csv_file)
381
+
382
+ debug_text = "\n".join(debug_info)
383
+
384
+ if not websites:
385
+ error_msg = "No websites found in the CSV file.\n\n"
386
+ error_msg += "DEBUG INFORMATION:\n" + debug_text + "\n\n"
387
+ error_msg += "TROUBLESHOOTING:\n"
388
+ error_msg += "1. Ensure your CSV has website URLs in column H (8th column)\n"
389
+ error_msg += "2. Or have a column header named 'website', 'url', 'domain', etc.\n"
390
+ error_msg += "3. Check that URLs are properly formatted (e.g., example.com or https://example.com)\n"
391
+ error_msg += "4. Verify the CSV file is not corrupted\n"
392
+ return error_msg, ""
393
+
394
+ all_contacts = []
395
+ processed_websites = []
396
+
397
+ # Search each website
398
+ for website in websites[:20]: # Limit to first 20 websites
399
+ print(f"Processing website: {website}")
400
+ contacts = simulate_website_scraping(website)
401
+ if contacts:
402
+ all_contacts.extend(contacts)
403
+ processed_websites.append(website)
404
+ print(f"Found {len(contacts)} contacts for {website}")
405
+ else:
406
+ print(f"No contacts found for {website}")
407
+
408
+ # Remove duplicates based on email
409
+ unique_contacts = []
410
+ seen_emails = set()
411
+ for contact in all_contacts:
412
+ if contact['email'] not in seen_emails:
413
+ unique_contacts.append(contact)
414
+ seen_emails.add(contact['email'])
415
+
416
+ # Limit results
417
+ unique_contacts = unique_contacts[:max_results]
418
+
419
+ if not unique_contacts:
420
+ result_msg = f"No contacts found for the {len(websites)} websites from the CSV file.\n\n"
421
+ result_msg += "DEBUG INFORMATION:\n" + debug_text + "\n\n"
422
+ result_msg += f"Websites processed: {', '.join(websites[:10])}\n"
423
+ result_msg += "This might be because the websites are not in our sample database."
424
+ return result_msg, ""
425
+
426
+ # Format results
427
+ results_text = f"CONTACT DISCOVERY REPORT\n"
428
+ results_text += f"CSV Processing Details:\n"
429
+ results_text += f"Total Websites in CSV: {len(websites)}\n"
430
+ results_text += f"Websites Processed: {len(processed_websites)}\n"
431
+ results_text += f"Websites with Contacts: {len(processed_websites)}\n"
432
+ results_text += f"Unique Contacts Found: {len(unique_contacts)}\n"
433
+ results_text += f"Processed Websites: {', '.join(processed_websites)}\n"
434
+ results_text += f"{'='*60}\n\n"
435
+
436
+ # Add debug info
437
+ results_text += "DEBUG INFORMATION:\n" + debug_text + "\n\n"
438
+ results_text += f"{'='*60}\n\n"
439
+
440
+ for i, contact in enumerate(unique_contacts, 1):
441
+ results_text += f"CONTACT #{i}\n"
442
+ results_text += f"Name: {contact['first_name']} {contact['last_name']}\n"
443
+ results_text += f"Position: {contact['job_title']}\n"
444
+ results_text += f"Email: {contact['email']}\n"
445
+ results_text += f"Phone: {contact['phone']}\n"
446
+ results_text += f"Company: {contact['company']}\n"
447
+ results_text += f"Website: {contact['website']}\n\n"
448
+
449
+ # Create CSV output
450
+ csv_output = "First Name,Last Name,Job Title,Email,Phone,Company,Website\n"
451
+ for contact in unique_contacts:
452
+ csv_output += f"{contact['first_name']},{contact['last_name']},{contact['job_title']},{contact['email']},{contact['phone']},{contact['company']},{contact['website']}\n"
453
+
454
+ return results_text, csv_output
455
+
456
+ except Exception as e:
457
+ return f"Error processing CSV file: {str(e)}", ""
458
+
459
+ def search_website_contacts(website_url, max_results=10):
460
+ """Main function to search for contacts on a website"""
461
+ if not website_url:
462
+ return "Please enter a website URL", ""
463
+
464
+ # Clean up URL
465
+ if not website_url.startswith(('http://', 'https://')):
466
+ website_url = 'https://' + website_url
467
+
468
+ try:
469
+ # Simulate finding contacts
470
+ contacts = simulate_website_scraping(website_url)
471
+
472
+ if not contacts:
473
+ return f"No contacts found on {website_url}. \n\nThis website is not in our contact database. Try one of the sample websites listed below, or the website might not have publicly available contact information.", ""
474
+
475
+ # Limit results
476
+ contacts = contacts[:max_results]
477
+
478
+ # Format results
479
+ results_text = f"CONTACT INTELLIGENCE REPORT\n"
480
+ results_text += f"Website: {website_url}\n"
481
+ results_text += f"Contacts Found: {len(contacts)}\n"
482
+ results_text += f"{'='*60}\n\n"
483
+
484
+ for i, contact in enumerate(contacts, 1):
485
+ results_text += f"CONTACT #{i}\n"
486
+ results_text += f"First Name: {contact['first_name']}\n"
487
+ results_text += f"Last Name: {contact['last_name']}\n"
488
+ results_text += f"Position: {contact['job_title']}\n"
489
+ results_text += f"Email: {contact['email']}\n"
490
+ results_text += f"Phone: {contact['phone']}\n"
491
+ results_text += f"Company: {contact['company']}\n\n"
492
+
493
+ # Create a simple table format for the second output
494
+ table_text = "First Name,Last Name,Job Title,Email,Phone,Company\n"
495
+ for contact in contacts:
496
+ table_text += f"{contact['first_name']},{contact['last_name']},{contact['job_title']},{contact['email']},{contact['phone']},{contact['company']}\n"
497
+
498
+ return results_text, table_text
499
+
500
+ except Exception as e:
501
+ return f"Error searching website: {str(e)}", ""
502
+
503
+ def get_all_available_websites():
504
+ """Get list of all available websites from the database"""
505
+ websites = list(set([contact['website'] for contact in CONTACTS_DB]))
506
+ return "\n".join(sorted(websites))
507
+
508
+ # Custom CSS
509
+ custom_css = """
510
+ .gradio-container {
511
+ background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
512
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
513
+ }
514
+
515
+ .main-header {
516
+ background: linear-gradient(135deg, #1e3a8a 0%, #3b82f6 50%, #1e40af 100%);
517
+ color: white;
518
+ padding: 40px 20px;
519
+ text-align: center;
520
+ border-radius: 15px;
521
+ margin-bottom: 30px;
522
+ box-shadow: 0 10px 30px rgba(30, 58, 138, 0.3);
523
+ }
524
+
525
+ .main-header h1 {
526
+ font-size: 2.5em;
527
+ margin: 0;
528
+ font-weight: 700;
529
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
530
+ }
531
+
532
+ .main-header p {
533
+ font-size: 1.2em;
534
+ margin: 15px 0 0 0;
535
+ opacity: 0.9;
536
+ }
537
+
538
+ .corporate-card {
539
+ background: white;
540
+ border: 1px solid #d1d5db;
541
+ border-radius: 12px;
542
+ padding: 25px;
543
+ margin: 15px 0;
544
+ box-shadow: 0 4px 15px rgba(0,0,0,0.1);
545
+ border-left: 5px solid #1e40af;
546
+ }
547
+
548
+ .tips-section {
549
+ background: linear-gradient(135deg, #f1f5f9 0%, #e2e8f0 100%);
550
+ border: 2px solid #cbd5e1;
551
+ border-radius: 15px;
552
+ padding: 20px;
553
+ margin: 10px 0;
554
+ }
555
+
556
+ .tips-section h3 {
557
+ color: #1e40af;
558
+ margin-top: 0;
559
+ font-weight: 600;
560
+ }
561
+
562
+ .primary-btn {
563
+ background: linear-gradient(135deg, #1e40af 0%, #3b82f6 100%);
564
+ color: white;
565
+ border: none;
566
+ border-radius: 8px;
567
+ padding: 15px 30px;
568
+ font-weight: 600;
569
+ font-size: 16px;
570
+ transition: all 0.3s ease;
571
+ }
572
+
573
+ .primary-btn:hover {
574
+ background: linear-gradient(135deg, #1e3a8a 0%, #2563eb 100%);
575
+ transform: translateY(-2px);
576
+ box-shadow: 0 6px 20px rgba(30, 64, 175, 0.4);
577
+ }
578
+
579
+ .secondary-btn {
580
+ background: white;
581
+ color: #374151;
582
+ border: 2px solid #d1d5db;
583
+ border-radius: 6px;
584
+ padding: 8px 16px;
585
+ font-weight: 500;
586
+ transition: all 0.3s ease;
587
+ }
588
+
589
+ .secondary-btn:hover {
590
+ border-color: #1e40af;
591
+ color: #1e40af;
592
+ background: #f8fafc;
593
+ }
594
+
595
+ .custom-input {
596
+ border: 2px solid #d1d5db;
597
+ border-radius: 8px;
598
+ padding: 12px;
599
+ font-size: 16px;
600
+ transition: border-color 0.3s ease;
601
+ }
602
+
603
+ .custom-input:focus {
604
+ border-color: #3b82f6;
605
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
606
+ }
607
+
608
+ .results-container {
609
+ background: white;
610
+ border: 1px solid #e5e7eb;
611
+ border-radius: 10px;
612
+ padding: 20px;
613
+ margin: 15px 0;
614
+ box-shadow: 0 2px 10px rgba(0,0,0,0.05);
615
+ }
616
+
617
+ .section-header {
618
+ background: linear-gradient(135deg, #64748b 0%, #475569 100%);
619
+ color: white;
620
+ padding: 15px 20px;
621
+ border-radius: 10px;
622
+ margin: 20px 0 15px 0;
623
+ font-weight: 600;
624
+ }
625
+ """
626
+
627
+ # Create Gradio interface
628
+ with gr.Blocks(css=custom_css, title="Contact Discovery Platform", theme=gr.themes.Base()) as app:
629
+ gr.HTML("""
630
+ <div class="main-header">
631
+ <h1>Contact Discovery Platform</h1>
632
+ <p>Professional Contact Discovery & Lead Generation Tool</p>
633
+ <p style="font-size: 0.95em; opacity: 0.8;">Advanced website analysis for contact intelligence gathering</p>
634
+ </div>
635
+ """)
636
+
637
+ with gr.Tabs():
638
+ # Single Website Search Tab
639
+ with gr.TabItem("Single Website Search"):
640
+ with gr.Row():
641
+ with gr.Column(scale=2):
642
+ gr.HTML('<div class="section-header">Search Parameters</div>')
643
+
644
+ website_input = gr.Textbox(
645
+ label="Target Website URL",
646
+ placeholder="Enter company website (e.g., techflowsolutions.com)",
647
+ value="",
648
+ elem_classes=["custom-input"]
649
+ )
650
+
651
+ with gr.Row():
652
+ max_results = gr.Slider(
653
+ minimum=1,
654
+ maximum=20,
655
+ value=8,
656
+ step=1,
657
+ label="Maximum Results",
658
+ elem_classes=["custom-input"]
659
+ )
660
+
661
+ search_btn = gr.Button(
662
+ "Execute Search",
663
+ variant="primary",
664
+ size="lg",
665
+ elem_classes=["primary-btn"]
666
+ )
667
+
668
+ gr.HTML('<div class="section-header">Search Results</div>')
669
+
670
+ with gr.Row():
671
+ results_display = gr.Textbox(
672
+ label="Contact Intelligence Report",
673
+ lines=18,
674
+ max_lines=35,
675
+ show_copy_button=True,
676
+ elem_classes=["results-container"]
677
+ )
678
+
679
+ csv_output = gr.Textbox(
680
+ label="Export Data (CSV Format)",
681
+ lines=18,
682
+ max_lines=35,
683
+ show_copy_button=True,
684
+ elem_classes=["results-container"]
685
+ )
686
+
687
+ # CSV Upload Tab
688
+ with gr.TabItem("CSV Bulk Search"):
689
+ with gr.Row():
690
+ with gr.Column(scale=2):
691
+ gr.HTML('<div class="section-header">CSV Upload</div>')
692
+
693
+ csv_file = gr.File(
694
+ label="Upload CSV File",
695
+ file_types=[".csv"],
696
+ elem_classes=["custom-input"]
697
+ )
698
+
699
+ gr.HTML("""
700
+ <div style="background: #f8fafc; padding: 15px; border-radius: 8px; border-left: 4px solid #1e40af; margin: 10px 0;">
701
+ <strong>CSV Format - Multiple Options:</strong><br>
702
+ <strong>Option 1:</strong> Website URLs in <strong>Column H (8th column)</strong><br>
703
+ <strong>Option 2:</strong> Column header named 'website', 'url', 'domain', 'site', or 'web'<br>
704
+ <strong>Option 3:</strong> System will auto-detect columns with valid URLs<br><br>
705
+ <strong>Examples:</strong> techflowsolutions.com, https://example.com, www.company.com<br>
706
+ <strong>Note:</strong> The system will show detailed debugging information about your CSV structure
707
+ </div>
708
+ """)
709
+
710
+ with gr.Row():
711
+ csv_max_results = gr.Slider(
712
+ minimum=1,
713
+ maximum=50,
714
+ value=20,
715
+ step=1,
716
+ label="Maximum Results",
717
+ elem_classes=["custom-input"]
718
+ )
719
+
720
+ csv_search_btn = gr.Button(
721
+ "Process CSV",
722
+ variant="primary",
723
+ size="lg",
724
+ elem_classes=["primary-btn"]
725
+ )
726
+
727
+ gr.HTML('<div class="section-header">CSV Results</div>')
728
+
729
+ with gr.Row():
730
+ csv_results_display = gr.Textbox(
731
+ label="CSV Processing Report",
732
+ lines=18,
733
+ max_lines=35,
734
+ show_copy_button=True,
735
+ elem_classes=["results-container"]
736
+ )
737
+
738
+ csv_export_output = gr.Textbox(
739
+ label="Export Data (CSV Format)",
740
+ lines=18,
741
+ max_lines=35,
742
+ show_copy_button=True,
743
+ elem_classes=["results-container"]
744
+ )
745
+
746
+ # Sample websites section
747
+ with gr.Accordion("Sample Websites Database", open=False):
748
+ gr.HTML('<div style="background: #f8fafc; padding: 15px; border-radius: 8px; border-left: 4px solid #1e40af;">')
749
+ sample_websites = gr.Textbox(
750
+ label="Available Websites in Database",
751
+ value=get_all_available_websites(),
752
+ lines=8,
753
+ interactive=False,
754
+ elem_classes=["custom-input"]
755
+ )
756
+ gr.HTML('</div>')
757
+
758
+ # Quick search buttons
759
+ gr.HTML('<div class="section-header">Quick Access Sample Websites</div>')
760
+
761
+ with gr.Row():
762
+ quick_btn1 = gr.Button("TechFlow Solutions", size="sm", elem_classes=["secondary-btn"])
763
+ quick_btn2 = gr.Button("GreenLeaf Consulting", size="sm", elem_classes=["secondary-btn"])
764
+ quick_btn3 = gr.Button("BlueSky Marketing", size="sm", elem_classes=["secondary-btn"])
765
+ quick_btn4 = gr.Button("Quantum Dynamics", size="sm", elem_classes=["secondary-btn"])
766
+
767
+ with gr.Row():
768
+ quick_btn5 = gr.Button("Stellar Logistics", size="sm", elem_classes=["secondary-btn"])
769
+ quick_btn6 = gr.Button("Nexus Financial", size="sm", elem_classes=["secondary-btn"])
770
+ quick_btn7 = gr.Button("Horizon Health", size="sm", elem_classes=["secondary-btn"])
771
+ quick_btn8 = gr.Button("Phoenix Manufacturing", size="sm", elem_classes=["secondary-btn"])
772
+
773
+ # Event handlers
774
+ search_btn.click(
775
+ fn=search_website_contacts,
776
+ inputs=[website_input, max_results],
777
+ outputs=[results_display, csv_output]
778
+ )
779
+
780
+ csv_search_btn.click(
781
+ fn=search_csv_websites,
782
+ inputs=[csv_file, csv_max_results],
783
+ outputs=[csv_results_display, csv_export_output]
784
+ )
785
+
786
+ # Quick search button handlers
787
+ quick_btn1.click(lambda: "techflowsolutions.com", outputs=website_input)
788
+ quick_btn2.click(lambda: "greenleafconsult.com", outputs=website_input)
789
+ quick_btn3.click(lambda: "blueskymarketing.net", outputs=website_input)
790
+ quick_btn4.click(lambda: "quantumdynamics.org", outputs=website_input)
791
+ quick_btn5.click(lambda: "stellarlogistics.biz", outputs=website_input)
792
+ quick_btn6.click(lambda: "nexusfinancial.pro", outputs=website_input)
793
+ quick_btn7.click(lambda: "horizonhealth.care", outputs=website_input)
794
+ quick_btn8.click(lambda: "phoenixmfg.com", outputs=website_input)
795
+
796
+ # Examples
797
+ gr.Examples(
798
+ examples=[
799
+ ["techflowsolutions.com", 5],
800
+ ["greenleafconsult.com", 3],
801
+ ["blueskymarketing.net", 4],
802
+ ["quantumdynamics.org", 6]
803
+ ],
804
+ inputs=[website_input, max_results],
805
+ label="Sample Searches"
806
+ )
807
+
808
+ # Footer
809
+ gr.HTML("""
810
+ <div style="text-align: center; padding: 30px 20px; background: linear-gradient(135deg, #64748b 0%, #475569 100%); color: white; border-radius: 15px; margin-top: 30px;">
811
+ <h3 style="margin: 0 0 10px 0;">Contact Intelligence Platform</h3>
812
+ <p style="margin: 0; opacity: 0.9;">Professional-grade contact discovery and lead generation technology</p>
813
+ <p style="margin: 10px 0 0 0; font-size: 0.9em; opacity: 0.7;">Powered by advanced web intelligence algorithms</p>
814
+ </div>
815
+ """)
816
+
817
+ if __name__ == "__main__":
818
+ app.launch()