JayBene1 commited on
Commit
287fad6
·
verified ·
1 Parent(s): fd7493b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +62 -227
app.py CHANGED
@@ -4,10 +4,9 @@ import json
4
  from typing import List, Dict, Any
5
  import pandas as pd
6
 
7
- # Hardcoded API endpoint - Updated to correct endpoint
8
  API_ENDPOINT = "https://jaybene1-testapicontacts.hf.space/contacts"
9
 
10
- # Professional color scheme inspired by corporate/real estate companies
11
  theme = gr.themes.Soft(
12
  primary_hue="blue",
13
  secondary_hue="slate",
@@ -16,96 +15,52 @@ theme = gr.themes.Soft(
16
  spacing_size="md",
17
  radius_size="md"
18
  ).set(
19
- body_background_fill="#f8fafc",
20
- body_background_fill_dark="#1e293b",
21
- block_background_fill="#ffffff",
22
- block_background_fill_dark="#334155",
23
- block_border_color="#e2e8f0",
24
- block_border_color_dark="#475569",
25
- input_background_fill="#ffffff",
26
- input_background_fill_dark="#334155",
27
- input_border_color="#cbd5e1",
28
- input_border_color_dark="#64748b",
29
  button_primary_background_fill="#1e40af",
30
  button_primary_background_fill_hover="#1d4ed8",
31
  button_primary_text_color="#ffffff",
32
- button_secondary_background_fill="#f1f5f9",
33
- button_secondary_background_fill_hover="#e2e8f0",
34
- button_secondary_text_color="#334155"
35
  )
36
 
37
  def search_contacts(url: str) -> tuple[str, str]:
38
- """
39
- Search for contacts associated with a given URL using the Hugging Face API.
40
-
41
- Args:
42
- url: The website URL to search for contacts
43
-
44
- Returns:
45
- Tuple of (formatted_results, raw_json)
46
- """
47
-
48
  if not url.strip():
49
  return "❌ Please enter a website URL", ""
50
-
51
- # Clean and validate URL
52
  url = url.strip()
53
  if not url.startswith(('http://', 'https://')):
54
  url = 'https://' + url
55
-
56
  try:
57
- # Use GET request with URL parameter
58
- params = {
59
- 'url': url
60
- }
61
-
62
- # Make the API request to the hardcoded endpoint using GET
63
- response = requests.get(
64
- API_ENDPOINT,
65
- params=params,
66
- timeout=30
67
- )
68
-
69
  if response.status_code == 200:
70
- try:
71
- result = response.json()
72
-
73
- # Add debugging info
74
- request_url = f"{API_ENDPOINT}?url={url}"
75
-
76
- # Hugging Face Spaces API returns data in a different format
77
- if isinstance(result, dict) and 'data' in result:
78
- actual_result = result['data'][0] if result['data'] else {}
79
- else:
80
- actual_result = result
81
-
82
- # Apply client-side filtering
83
- if isinstance(actual_result, list):
84
- actual_result = filter_contacts_by_url(actual_result, url)
85
- elif isinstance(actual_result, dict) and 'contacts' in actual_result:
86
- actual_result['contacts'] = filter_contacts_by_url(actual_result['contacts'], url)
87
-
88
- # Format the results for display
89
- formatted_output = format_contact_results(actual_result, url)
90
-
91
- # Add debugging info to the formatted output
92
- debug_info = f"\n\n**Debug Info:**\n"
93
- debug_info += f"- Request URL: {API_ENDPOINT}\n"
94
- debug_info += f"- Search URL: {url}\n"
95
- debug_info += f"- Response contains {len(actual_result) if isinstance(actual_result, list) else 'N/A'} items\n"
96
- debug_info += f"- Client-side filtering applied\n"
97
-
98
- formatted_output += debug_info
99
- raw_json = json.dumps(result, indent=2)
100
-
101
- return formatted_output, raw_json
102
-
103
- except json.JSONDecodeError:
104
- return f"❌ Error: Invalid JSON response from API", response.text
105
-
106
  else:
107
  return f"❌ API Error ({response.status_code}): {response.text}", ""
108
-
109
  except requests.exceptions.Timeout:
110
  return "❌ Request timeout. Please try again.", ""
111
  except requests.exceptions.ConnectionError:
@@ -114,21 +69,12 @@ def search_contacts(url: str) -> tuple[str, str]:
114
  return f"❌ Error: {str(e)}", ""
115
 
116
  def filter_contacts_by_url(contacts, search_url):
117
- """
118
- Filter contacts based on the search URL.
119
- This is a client-side filter in case the API doesn't filter properly.
120
- """
121
  if not isinstance(contacts, list):
122
  return contacts
123
-
124
- # Extract domain from search URL
125
  search_domain = search_url.replace('https://', '').replace('http://', '').replace('www.', '').split('/')[0].lower()
126
-
127
  filtered_contacts = []
128
  for contact in contacts:
129
- # Check if contact is associated with the search domain
130
  if isinstance(contact, dict):
131
- # Check various fields that might contain the domain
132
  fields_to_check = [
133
  contact.get('website', ''),
134
  contact.get('company_website', ''),
@@ -138,126 +84,54 @@ def filter_contacts_by_url(contacts, search_url):
138
  str(contact.get('url', '')),
139
  str(contact.get('source', ''))
140
  ]
141
-
142
- # Check if any field contains the search domain
143
  for field in fields_to_check:
144
  if field and search_domain in str(field).lower():
145
  filtered_contacts.append(contact)
146
  break
147
-
148
  return filtered_contacts if filtered_contacts else contacts
149
 
150
  def format_contact_results(results: Dict[Any, Any], url: str) -> str:
151
- """
152
- Format the API results into a readable format.
153
-
154
- Args:
155
- results: The JSON response from the API
156
- url: The searched URL
157
-
158
- Returns:
159
- Formatted string with contact information
160
- """
161
-
162
  output = f"# Contact Search Results for: {url}\n\n"
163
-
164
- # Handle different possible result structures
165
  if isinstance(results, dict):
166
- if 'contacts' in results:
167
- contacts = results['contacts']
168
- elif 'results' in results:
169
- contacts = results['results']
170
- elif 'data' in results:
171
- contacts = results['data']
172
- else:
173
- contacts = results
174
-
175
- if isinstance(contacts, list) and len(contacts) > 0:
176
  output += f"**Found {len(contacts)} contact(s):**\n\n"
177
-
178
  for i, contact in enumerate(contacts, 1):
179
  output += f"## Contact {i}\n"
180
-
181
- # Handle different contact field names
182
  name = contact.get('name') or contact.get('full_name') or contact.get('contact_name') or "N/A"
183
  email = contact.get('email') or contact.get('email_address') or "N/A"
184
  title = contact.get('title') or contact.get('job_title') or contact.get('position') or "N/A"
185
  company = contact.get('company') or contact.get('organization') or "N/A"
186
  phone = contact.get('phone') or contact.get('phone_number') or "N/A"
187
  linkedin = contact.get('linkedin') or contact.get('linkedin_url') or "N/A"
188
-
189
- output += f"- **Name:** {name}\n"
190
- output += f"- **Email:** {email}\n"
191
- output += f"- **Title:** {title}\n"
192
- output += f"- **Company:** {company}\n"
193
- output += f"- **Phone:** {phone}\n"
194
- output += f"- **LinkedIn:** {linkedin}\n\n"
195
-
196
- # Add any additional fields
197
- additional_fields = {k: v for k, v in contact.items()
198
- if k not in ['name', 'full_name', 'contact_name', 'email', 'email_address',
199
- 'title', 'job_title', 'position', 'company', 'organization',
200
- 'phone', 'phone_number', 'linkedin', 'linkedin_url']}
201
-
202
  if additional_fields:
203
  output += "**Additional Information:**\n"
204
  for key, value in additional_fields.items():
205
  output += f"- **{key.replace('_', ' ').title()}:** {value}\n"
206
  output += "\n"
207
-
208
  output += "---\n\n"
209
-
210
  else:
211
  output += "No contacts found for this URL.\n\n"
212
-
213
  elif isinstance(results, list):
214
- if len(results) > 0:
215
  output += f"**Found {len(results)} contact(s):**\n\n"
216
  for i, contact in enumerate(results, 1):
217
- output += f"## Contact {i}\n"
218
- output += f"{contact}\n\n"
219
  else:
220
  output += "No contacts found for this URL.\n\n"
221
  else:
222
  output += f"**Result:** {results}\n\n"
223
-
224
  output += f"*Search completed at: {pd.Timestamp.now().strftime('%Y-%m-%d %H:%M:%S')}*"
225
-
226
  return output
227
 
228
- def create_sample_data():
229
- """Create sample data for demonstration"""
230
- return '''# Contact Search Results for: example.com
231
-
232
- **Found 2 contact(s):**
233
-
234
- ## Contact 1
235
- - **Name:** John Smith
236
- - **Email:** john.smith@example.com
237
- - **Title:** CEO
238
- - **Company:** Example Corp
239
- - **Phone:** (555) 123-4567
240
- - **LinkedIn:** linkedin.com/in/johnsmith
241
-
242
- ---
243
-
244
- ## Contact 2
245
- - **Name:** Jane Doe
246
- - **Email:** jane.doe@example.com
247
- - **Title:** VP of Sales
248
- - **Company:** Example Corp
249
- - **Phone:** (555) 123-4568
250
- - **LinkedIn:** linkedin.com/in/janedoe
251
-
252
- ---
253
-
254
- *Search completed at: 2025-01-15 10:30:00*'''
255
-
256
- # Create the Gradio interface
257
- with gr.Blocks(theme=theme, title="Contact Search - Kwekel Companies", css="""
258
  .gradio-container {
259
  max-width: 1200px !important;
260
  margin: 0 auto !important;
 
 
261
  }
262
  .header {
263
  background: linear-gradient(135deg, #1e40af 0%, #3b82f6 100%);
@@ -271,103 +145,64 @@ with gr.Blocks(theme=theme, title="Contact Search - Kwekel Companies", css="""
271
  margin: 0;
272
  font-size: 2.5rem;
273
  font-weight: 700;
274
- margin-bottom: 0.5rem;
275
- }
276
- .header p {
277
- margin: 0;
278
- font-size: 1.2rem;
279
- opacity: 0.9;
280
  }
281
  .info-box {
282
- background: #f0f9ff;
283
- border: 1px solid #0ea5e9;
284
  border-radius: 0.5rem;
285
  padding: 1rem;
286
  margin: 1rem 0;
 
287
  }
288
  .footer {
289
  text-align: center;
290
  margin-top: 2rem;
291
  padding-top: 2rem;
292
- border-top: 1px solid #e2e8f0;
293
- color: #64748b;
294
  }
295
  """) as demo:
296
 
297
- # Header
298
  gr.HTML("""
299
  <div class="header">
300
- <h1>Contact Search Tool</h1>
301
- <p>Professional contact discovery powered by AI</p>
302
  </div>
303
  """)
304
-
305
- # Info box
306
  gr.HTML(f"""
307
  <div class="info-box">
308
  <h3>Instructions:</h3>
309
  <ol>
310
- <li>Enter the website URL you want to search for contacts</li>
311
- <li>Click "Search Contacts" to get results</li>
312
- <li>View formatted results and raw JSON response</li>
313
  </ol>
314
  <p><strong>API Endpoint:</strong> {API_ENDPOINT}</p>
315
  </div>
316
  """)
317
-
318
  with gr.Row():
319
  with gr.Column(scale=2):
320
- url_input = gr.Textbox(
321
- label="Website URL",
322
- placeholder="example.com or https://example.com",
323
- info="Enter the website URL to search for contacts",
324
- lines=1
325
- )
326
-
327
  with gr.Row():
328
  search_btn = gr.Button("Search Contacts", variant="primary", scale=2)
329
- demo_btn = gr.Button("Show Demo", variant="secondary", scale=1)
330
  clear_btn = gr.Button("Clear", variant="secondary", scale=1)
331
-
332
  with gr.Row():
333
  with gr.Column(scale=1):
334
- results_output = gr.Markdown(
335
- label="Contact Results",
336
- value="Enter a URL and click 'Search Contacts' to see results here."
337
- )
338
-
339
  with gr.Column(scale=1):
340
- json_output = gr.Code(
341
- label="Raw JSON Response",
342
- language="json",
343
- value=""
344
- )
345
-
346
- # Event handlers
347
- search_btn.click(
348
- fn=search_contacts,
349
- inputs=[url_input],
350
- outputs=[results_output, json_output]
351
- )
352
-
353
- demo_btn.click(
354
- fn=lambda: (create_sample_data(), '{"contacts": [{"name": "John Smith", "email": "john.smith@example.com", "title": "CEO"}]}'),
355
- outputs=[results_output, json_output]
356
- )
357
-
358
- clear_btn.click(
359
- fn=lambda: ("", ""),
360
- outputs=[url_input, results_output]
361
- )
362
-
363
- # Footer
364
  gr.HTML("""
365
  <div class="footer">
366
- <p>© 2025 Contact Search Tool - Professional contact discovery solution</p>
367
  </div>
368
  """)
369
 
370
- # Launch the app
371
  if __name__ == "__main__":
372
  demo.launch(
373
  share=True,
@@ -375,4 +210,4 @@ if __name__ == "__main__":
375
  server_port=7860,
376
  show_error=True,
377
  debug=True
378
- )
 
4
  from typing import List, Dict, Any
5
  import pandas as pd
6
 
 
7
  API_ENDPOINT = "https://jaybene1-testapicontacts.hf.space/contacts"
8
 
9
+ # Custom theme inspired by image
10
  theme = gr.themes.Soft(
11
  primary_hue="blue",
12
  secondary_hue="slate",
 
15
  spacing_size="md",
16
  radius_size="md"
17
  ).set(
18
+ body_background_fill="#0f172a", # Very dark blue-gray
19
+ body_background_fill_dark="#0f172a",
20
+ block_background_fill="#1e293b", # Slightly lighter for blocks
21
+ block_background_fill_dark="#1e293b",
22
+ block_border_color="#334155",
23
+ block_border_color_dark="#334155",
24
+ input_background_fill="#1e293b",
25
+ input_background_fill_dark="#1e293b",
26
+ input_border_color="#475569",
27
+ input_border_color_dark="#475569",
28
  button_primary_background_fill="#1e40af",
29
  button_primary_background_fill_hover="#1d4ed8",
30
  button_primary_text_color="#ffffff",
31
+ button_secondary_background_fill="#334155",
32
+ button_secondary_background_fill_hover="#475569",
33
+ button_secondary_text_color="#f8fafc"
34
  )
35
 
36
  def search_contacts(url: str) -> tuple[str, str]:
 
 
 
 
 
 
 
 
 
 
37
  if not url.strip():
38
  return "❌ Please enter a website URL", ""
 
 
39
  url = url.strip()
40
  if not url.startswith(('http://', 'https://')):
41
  url = 'https://' + url
42
+
43
  try:
44
+ response = requests.get(API_ENDPOINT, params={'url': url}, timeout=30)
 
 
 
 
 
 
 
 
 
 
 
45
  if response.status_code == 200:
46
+ result = response.json()
47
+ request_url = f"{API_ENDPOINT}?url={url}"
48
+ actual_result = result.get('data', [])[0] if isinstance(result, dict) and 'data' in result else result
49
+ if isinstance(actual_result, list):
50
+ actual_result = filter_contacts_by_url(actual_result, url)
51
+ elif isinstance(actual_result, dict) and 'contacts' in actual_result:
52
+ actual_result['contacts'] = filter_contacts_by_url(actual_result['contacts'], url)
53
+ formatted_output = format_contact_results(actual_result, url)
54
+ formatted_output += (
55
+ f"\n\n**Debug Info:**\n"
56
+ f"- Request URL: {API_ENDPOINT}\n"
57
+ f"- Search URL: {url}\n"
58
+ f"- Response contains {len(actual_result) if isinstance(actual_result, list) else 'N/A'} items\n"
59
+ f"- Client-side filtering applied\n"
60
+ )
61
+ return formatted_output, json.dumps(result, indent=2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  else:
63
  return f"❌ API Error ({response.status_code}): {response.text}", ""
 
64
  except requests.exceptions.Timeout:
65
  return "❌ Request timeout. Please try again.", ""
66
  except requests.exceptions.ConnectionError:
 
69
  return f"❌ Error: {str(e)}", ""
70
 
71
  def filter_contacts_by_url(contacts, search_url):
 
 
 
 
72
  if not isinstance(contacts, list):
73
  return contacts
 
 
74
  search_domain = search_url.replace('https://', '').replace('http://', '').replace('www.', '').split('/')[0].lower()
 
75
  filtered_contacts = []
76
  for contact in contacts:
 
77
  if isinstance(contact, dict):
 
78
  fields_to_check = [
79
  contact.get('website', ''),
80
  contact.get('company_website', ''),
 
84
  str(contact.get('url', '')),
85
  str(contact.get('source', ''))
86
  ]
 
 
87
  for field in fields_to_check:
88
  if field and search_domain in str(field).lower():
89
  filtered_contacts.append(contact)
90
  break
 
91
  return filtered_contacts if filtered_contacts else contacts
92
 
93
  def format_contact_results(results: Dict[Any, Any], url: str) -> str:
 
 
 
 
 
 
 
 
 
 
 
94
  output = f"# Contact Search Results for: {url}\n\n"
 
 
95
  if isinstance(results, dict):
96
+ contacts = results.get('contacts') or results.get('results') or results.get('data') or results
97
+ if isinstance(contacts, list) and contacts:
 
 
 
 
 
 
 
 
98
  output += f"**Found {len(contacts)} contact(s):**\n\n"
 
99
  for i, contact in enumerate(contacts, 1):
100
  output += f"## Contact {i}\n"
 
 
101
  name = contact.get('name') or contact.get('full_name') or contact.get('contact_name') or "N/A"
102
  email = contact.get('email') or contact.get('email_address') or "N/A"
103
  title = contact.get('title') or contact.get('job_title') or contact.get('position') or "N/A"
104
  company = contact.get('company') or contact.get('organization') or "N/A"
105
  phone = contact.get('phone') or contact.get('phone_number') or "N/A"
106
  linkedin = contact.get('linkedin') or contact.get('linkedin_url') or "N/A"
107
+ output += f"- **Name:** {name}\n- **Email:** {email}\n- **Title:** {title}\n- **Company:** {company}\n- **Phone:** {phone}\n- **LinkedIn:** {linkedin}\n\n"
108
+ additional_fields = {k: v for k, v in contact.items() if k not in ['name', 'full_name', 'contact_name', 'email', 'email_address', 'title', 'job_title', 'position', 'company', 'organization', 'phone', 'phone_number', 'linkedin', 'linkedin_url']}
 
 
 
 
 
 
 
 
 
 
 
 
109
  if additional_fields:
110
  output += "**Additional Information:**\n"
111
  for key, value in additional_fields.items():
112
  output += f"- **{key.replace('_', ' ').title()}:** {value}\n"
113
  output += "\n"
 
114
  output += "---\n\n"
 
115
  else:
116
  output += "No contacts found for this URL.\n\n"
 
117
  elif isinstance(results, list):
118
+ if results:
119
  output += f"**Found {len(results)} contact(s):**\n\n"
120
  for i, contact in enumerate(results, 1):
121
+ output += f"## Contact {i}\n{contact}\n\n"
 
122
  else:
123
  output += "No contacts found for this URL.\n\n"
124
  else:
125
  output += f"**Result:** {results}\n\n"
 
126
  output += f"*Search completed at: {pd.Timestamp.now().strftime('%Y-%m-%d %H:%M:%S')}*"
 
127
  return output
128
 
129
+ with gr.Blocks(theme=theme, title="Kwekel Companies Contact Search Tool", css="""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  .gradio-container {
131
  max-width: 1200px !important;
132
  margin: 0 auto !important;
133
+ background-color: #0f172a !important;
134
+ color: #f8fafc !important;
135
  }
136
  .header {
137
  background: linear-gradient(135deg, #1e40af 0%, #3b82f6 100%);
 
145
  margin: 0;
146
  font-size: 2.5rem;
147
  font-weight: 700;
 
 
 
 
 
 
148
  }
149
  .info-box {
150
+ background: #1e293b;
151
+ border: 1px solid #3b82f6;
152
  border-radius: 0.5rem;
153
  padding: 1rem;
154
  margin: 1rem 0;
155
+ color: #f8fafc;
156
  }
157
  .footer {
158
  text-align: center;
159
  margin-top: 2rem;
160
  padding-top: 2rem;
161
+ border-top: 1px solid #475569;
162
+ color: #94a3b8;
163
  }
164
  """) as demo:
165
 
 
166
  gr.HTML("""
167
  <div class="header">
168
+ <h1>Kwekel Companies Contact Search Tool</h1>
 
169
  </div>
170
  """)
171
+
 
172
  gr.HTML(f"""
173
  <div class="info-box">
174
  <h3>Instructions:</h3>
175
  <ol>
176
+ <li>Enter the website URL you want to search for contacts.</li>
177
+ <li>Click "Search Contacts" to get results.</li>
178
+ <li>View formatted results and raw JSON response.</li>
179
  </ol>
180
  <p><strong>API Endpoint:</strong> {API_ENDPOINT}</p>
181
  </div>
182
  """)
183
+
184
  with gr.Row():
185
  with gr.Column(scale=2):
186
+ url_input = gr.Textbox(label="Website URL", placeholder="example.com or https://example.com", lines=1)
 
 
 
 
 
 
187
  with gr.Row():
188
  search_btn = gr.Button("Search Contacts", variant="primary", scale=2)
 
189
  clear_btn = gr.Button("Clear", variant="secondary", scale=1)
190
+
191
  with gr.Row():
192
  with gr.Column(scale=1):
193
+ results_output = gr.Markdown(label="Contact Results", value="Enter a URL and click 'Search Contacts' to see results here.")
 
 
 
 
194
  with gr.Column(scale=1):
195
+ json_output = gr.Code(label="Raw JSON Response", language="json", value="")
196
+
197
+ search_btn.click(fn=search_contacts, inputs=[url_input], outputs=[results_output, json_output])
198
+ clear_btn.click(fn=lambda: ("", ""), outputs=[url_input, results_output])
199
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
  gr.HTML("""
201
  <div class="footer">
202
+ <p>© 2025 Kwekel Companies Contact Search Tool</p>
203
  </div>
204
  """)
205
 
 
206
  if __name__ == "__main__":
207
  demo.launch(
208
  share=True,
 
210
  server_port=7860,
211
  show_error=True,
212
  debug=True
213
+ )