CCockrum commited on
Commit
a77b9dd
·
verified ·
1 Parent(s): de07816

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +22 -363
app.py CHANGED
@@ -1,8 +1,5 @@
1
  import streamlit as st
2
  import requests
3
- import pandas as pd
4
- import json
5
- from datetime import datetime
6
  import time
7
  import os
8
 
@@ -57,47 +54,31 @@ st.markdown("""
57
  """, unsafe_allow_html=True)
58
 
59
  # Initialize session state variables
60
- if 'access_token' not in st.session_state:
61
- st.session_state.access_token = None
62
- if 'token_expires' not in st.session_state:
63
- st.session_state.token_expires = 0
64
- if 'search_results' not in st.session_state:
65
- st.session_state.search_results = None
66
- if 'selected_pet' not in st.session_state:
67
- st.session_state.selected_pet = None
68
- if 'page' not in st.session_state:
69
- st.session_state.page = 1
70
- if 'favorites' not in st.session_state:
71
- st.session_state.favorites = []
72
 
73
  # Function to get access token
74
  def get_access_token():
75
- # Check if token is still valid
76
  if st.session_state.access_token and time.time() < st.session_state.token_expires:
77
  return st.session_state.access_token
78
-
79
- # Get API credentials from environment variables or secrets
80
  api_key = os.environ.get('PETFINDER_API_KEY') or st.secrets.get('PETFINDER_API_KEY')
81
  api_secret = os.environ.get('PETFINDER_API_SECRET') or st.secrets.get('PETFINDER_API_SECRET')
82
-
83
  if not api_key or not api_secret:
84
- st.error("⚠️ Petfinder API credentials are missing. Please set them in your environment variables or Streamlit secrets.")
85
  return None
86
-
87
- # Get new token
88
  url = "https://api.petfinder.com/v2/oauth2/token"
89
- data = {
90
- "grant_type": "client_credentials",
91
- "client_id": api_key,
92
- "client_secret": api_secret
93
- }
94
-
95
  try:
96
  response = requests.post(url, data=data)
97
  response.raise_for_status()
98
  token_data = response.json()
99
  st.session_state.access_token = token_data['access_token']
100
- st.session_state.token_expires = time.time() + token_data['expires_in'] - 60 # Buffer of 60 seconds
101
  return st.session_state.access_token
102
  except requests.exceptions.RequestException as e:
103
  st.error(f"⚠️ Error getting access token: {str(e)}")
@@ -108,10 +89,8 @@ def search_pets(params):
108
  token = get_access_token()
109
  if not token:
110
  return None
111
-
112
  url = "https://api.petfinder.com/v2/animals"
113
  headers = {"Authorization": f"Bearer {token}"}
114
-
115
  try:
116
  response = requests.get(url, headers=headers, params=params)
117
  response.raise_for_status()
@@ -120,50 +99,13 @@ def search_pets(params):
120
  st.error(f"⚠️ Error searching pets: {str(e)}")
121
  return None
122
 
123
- # Function to get breeds
124
- def get_breeds(animal_type):
125
- token = get_access_token()
126
- if not token:
127
- return []
128
-
129
- url = f"https://api.petfinder.com/v2/types/{animal_type}/breeds"
130
- headers = {"Authorization": f"Bearer {token}"}
131
-
132
- try:
133
- response = requests.get(url, headers=headers)
134
- response.raise_for_status()
135
- return [breed['name'] for breed in response.json()['breeds']]
136
- except requests.exceptions.RequestException as e:
137
- st.error(f"⚠️ Error getting breeds: {str(e)}")
138
- return []
139
-
140
- # Function to get organizations
141
- def get_organizations(location):
142
- token = get_access_token()
143
- if not token:
144
- return []
145
-
146
- url = "https://api.petfinder.com/v2/organizations"
147
- headers = {"Authorization": f"Bearer {token}"}
148
- params = {"location": location, "distance": 100, "limit": 100}
149
-
150
- try:
151
- response = requests.get(url, headers=headers, params=params)
152
- response.raise_for_status()
153
- return [(org['id'], org['name']) for org in response.json()['organizations']]
154
- except requests.exceptions.RequestException as e:
155
- st.error(f"⚠️ Error getting organizations: {str(e)}")
156
- return []
157
-
158
  # Function to get pet details
159
  def get_pet_details(pet_id):
160
  token = get_access_token()
161
  if not token:
162
  return None
163
-
164
  url = f"https://api.petfinder.com/v2/animals/{pet_id}"
165
  headers = {"Authorization": f"Bearer {token}"}
166
-
167
  try:
168
  response = requests.get(url, headers=headers)
169
  response.raise_for_status()
@@ -175,357 +117,74 @@ def get_pet_details(pet_id):
175
  # Function to format pet card
176
  def display_pet_card(pet, is_favorite=False):
177
  col1, col2 = st.columns([1, 2])
178
-
179
  with col1:
180
  if pet['photos'] and len(pet['photos']) > 0:
181
  st.image(pet['photos'][0]['medium'], use_container_width=True)
182
  else:
183
  st.image("https://via.placeholder.com/300x300?text=No+Image", use_container_width=True)
184
-
185
  with col2:
186
  st.markdown(f"<div class='pet-name'>{pet['name']}</div>", unsafe_allow_html=True)
187
-
188
- # Tags
189
  tags_html = ""
190
  if pet['status'] == 'adoptable':
191
  tags_html += "<span class='tag' style='background-color: #c8e6c9;'>Adoptable</span> "
192
  else:
193
  tags_html += f"<span class='tag' style='background-color: #ffcdd2;'>{pet['status'].title()}</span> "
194
-
195
  if pet['age']:
196
  tags_html += f"<span class='tag'>{pet['age']}</span> "
197
  if pet['gender']:
198
  tags_html += f"<span class='tag'>{pet['gender']}</span> "
199
  if pet['size']:
200
  tags_html += f"<span class='tag'>{pet['size']}</span> "
201
-
202
  st.markdown(f"<div>{tags_html}</div>", unsafe_allow_html=True)
203
-
204
- st.markdown("<div class='pet-details'>", unsafe_allow_html=True)
205
- if pet['breeds']['primary']:
206
- breed_text = pet['breeds']['primary']
207
- if pet['breeds']['secondary']:
208
- breed_text += f" & {pet['breeds']['secondary']}"
209
- if pet['breeds']['mixed']:
210
- breed_text += " (Mixed)"
211
- st.markdown(f"<strong>Breed:</strong> {breed_text}", unsafe_allow_html=True)
212
-
213
- if pet['colors']['primary'] or pet['colors']['secondary'] or pet['colors']['tertiary']:
214
- colors = [c for c in [pet['colors']['primary'], pet['colors']['secondary'], pet['colors']['tertiary']] if c]
215
- st.markdown(f"<strong>Colors:</strong> {', '.join(colors)}", unsafe_allow_html=True)
216
-
217
- if 'location' in pet and pet['contact']['address']['city'] and pet['contact']['address']['state']:
218
- st.markdown(f"<strong>Location:</strong> {pet['contact']['address']['city']}, {pet['contact']['address']['state']}", unsafe_allow_html=True)
219
-
220
- st.markdown("</div>", unsafe_allow_html=True)
221
-
222
- if pet['description']:
223
- st.markdown(f"<div class='pet-description'>{pet['description'][:150]}{'...' if len(pet['description']) > 150 else ''}</div>", unsafe_allow_html=True)
224
-
225
- col1, col2 = st.columns(2)
226
- with col1:
227
- if st.button("View Details", key=f"details_{pet['id']}"):
228
- if st.session_state.selected_pet != pet['id']:
229
- st.session_state.selected_pet = pet['id']
230
- st.experimental_rerun() # Force immediate rerun
231
 
232
- with col2:
233
- if not is_favorite:
234
- if st.button("Add to Favorites", key=f"fav_{pet['id']}"):
235
- if pet['id'] not in [p['id'] for p in st.session_state.favorites]:
236
- st.session_state.favorites.append(pet)
237
- st.success(f"Added {pet['name']} to favorites!")
238
- st.experimental_rerun()
239
- else:
240
- if st.button("Remove from Favorites", key=f"unfav_{pet['id']}"):
241
- st.session_state.favorites = [p for p in st.session_state.favorites if p['id'] != pet['id']]
242
- st.success(f"Removed {pet['name']} from favorites!")
243
- st.experimental_rerun()
244
-
245
- # Function to generate pet compatibility message
246
- def get_compatibility_message(pet):
247
- messages = []
248
-
249
- # Check for kids
250
- if 'children' in pet['environment'] and pet['environment']['children'] is not None:
251
- if pet['environment']['children']:
252
- messages.append("✅ Good with children")
253
- else:
254
- messages.append("❌ Not recommended for homes with children")
255
-
256
- # Check for dogs
257
- if 'dogs' in pet['environment'] and pet['environment']['dogs'] is not None:
258
- if pet['environment']['dogs']:
259
- messages.append("✅ Good with dogs")
260
- else:
261
- messages.append("❌ Not recommended for homes with dogs")
262
-
263
- # Check for cats
264
- if 'cats' in pet['environment'] and pet['environment']['cats'] is not None:
265
- if pet['environment']['cats']:
266
- messages.append("✅ Good with cats")
267
- else:
268
- messages.append("❌ Not recommended for homes with cats")
269
-
270
- # Handling care needs
271
- if pet['attributes']:
272
- if 'special_needs' in pet['attributes'] and pet['attributes']['special_needs']:
273
- messages.append("⚠️ Has special needs")
274
-
275
- if 'house_trained' in pet['attributes'] and pet['attributes']['house_trained']:
276
- messages.append("✅ House-trained")
277
- elif 'house_trained' in pet['attributes']:
278
- messages.append("❌ Not house-trained")
279
-
280
- if 'shots_current' in pet['attributes'] and pet['attributes']['shots_current']:
281
- messages.append("✅ Vaccinations up to date")
282
-
283
- if 'spayed_neutered' in pet['attributes'] and pet['attributes']['spayed_neutered']:
284
- messages.append("✅ Spayed/neutered")
285
-
286
- return messages
287
 
288
  # Function to display pet details page
289
  def display_pet_details(pet_id):
290
  pet = get_pet_details(pet_id)
291
  if not pet:
292
- st.error("Unable to retrieve pet details. Please try again.")
293
  return
294
-
295
- # Back button
296
  if st.button("← Back to Search Results"):
297
  if st.session_state.selected_pet is not None:
298
  st.session_state.selected_pet = None
299
- st.experimental_rerun() # Force immediate rerun
300
-
301
- # Pet name and status
302
- st.markdown(f"<h1 class='main-header'>{pet['name']}</h1>", unsafe_allow_html=True)
303
-
304
- status_color = "#c8e6c9" if pet['status'] == 'adoptable' else "#ffcdd2"
305
- st.markdown(f"<div style='text-align: center;'><span class='tag' style='background-color: {status_color}; font-size: 1rem;'>{pet['status'].title()}</span></div>", unsafe_allow_html=True)
306
-
307
- # Pet photos
308
- if pet['photos'] and len(pet['photos']) > 0:
309
- photo_cols = st.columns(min(3, len(pet['photos'])))
310
- for i, col in enumerate(photo_cols):
311
- if i < len(pet['photos']):
312
- col.image(pet['photos'][i]['large'], use_container_width=True)
313
- else:
314
- st.image("https://via.placeholder.com/500x300?text=No+Image", use_container_width=True)
315
-
316
- # Pet details
317
- col1, col2 = st.columns(2)
318
-
319
- with col1:
320
- st.markdown("### Details")
321
- # Fix the breed line
322
- breed_text = pet['breeds']['primary']
323
- if pet['breeds']['secondary']:
324
- breed_text += f" & {pet['breeds']['secondary']}"
325
- if pet['breeds']['mixed']:
326
- breed_text += " (Mixed)"
327
-
328
- details = [
329
- f"**Type:** {pet['type']}",
330
- f"**Breed:** {breed_text}",
331
- f"**Age:** {pet['age']}",
332
- f"**Gender:** {pet['gender']}",
333
- f"**Size:** {pet['size']}"
334
- ]
335
-
336
- # Fix the colors line as well, to be safe
337
- colors = [c for c in [pet['colors']['primary'], pet['colors']['secondary'], pet['colors']['tertiary']] if c]
338
- if colors:
339
- details.append(f"**Colors:** {', '.join(colors)}")
340
-
341
- for detail in details:
342
- st.markdown(detail)
343
-
344
- with col2:
345
- st.markdown("### Compatibility")
346
- compatibility = get_compatibility_message(pet)
347
- for msg in compatibility:
348
- st.markdown(msg)
349
-
350
- # Description
351
- if pet['description']:
352
- st.markdown("### About")
353
- st.markdown(pet['description'])
354
-
355
- # Contact information
356
- st.markdown("### Adoption Information")
357
-
358
- # Organization info
359
- if pet['organization_id']:
360
- st.markdown(f"**Organization:** {pet['organization_id']}")
361
-
362
- # Contact details
363
- contact_info = []
364
- if pet['contact']['email']:
365
- contact_info.append(f"**Email:** {pet['contact']['email']}")
366
- if pet['contact']['phone']:
367
- contact_info.append(f"**Phone:** {pet['contact']['phone']}")
368
- if pet['contact']['address']['city'] and pet['contact']['address']['state']:
369
- contact_info.append(f"**Location:** {pet['contact']['address']['city']}, {pet['contact']['address']['state']} {pet['contact']['address']['postcode'] or ''}")
370
-
371
- for info in contact_info:
372
- st.markdown(info)
373
-
374
- # URL to pet on Petfinder
375
- if pet['url']:
376
- st.markdown(f"[View on Petfinder]({pet['url']})")
377
-
378
- # Add to favorites
379
- is_favorite = pet['id'] in [p['id'] for p in st.session_state.favorites]
380
- if not is_favorite:
381
- if st.button("Add to Favorites"):
382
- st.session_state.favorites.append(pet)
383
- st.success(f"Added {pet['name']} to favorites!")
384
- st.experimental_rerun()
385
- else:
386
- if st.button("Remove from Favorites"):
387
- st.session_state.favorites = [p for p in st.session_state.favorites if p['id'] != pet['id']]
388
- st.success(f"Removed {pet['name']} from favorites!")
389
  st.experimental_rerun()
 
390
 
391
  # Main app
392
  def main():
393
- # Title
394
  st.markdown("<h1 class='main-header'>🐾 PetMatch</h1>", unsafe_allow_html=True)
395
  st.markdown("<p class='sub-header'>Find your perfect pet companion</p>", unsafe_allow_html=True)
396
-
397
- # Create tabs
398
  tab1, tab2, tab3 = st.tabs(["Search", "Favorites", "About"])
399
-
400
  with tab1:
401
- # If a pet is selected, show details
402
  if st.session_state.selected_pet:
403
  display_pet_details(st.session_state.selected_pet)
404
  else:
405
- # Search form
406
  with st.expander("Search Options", expanded=True):
407
  with st.form("pet_search_form"):
408
  col1, col2 = st.columns(2)
409
-
410
  with col1:
411
- animal_type = st.selectbox(
412
- "Animal Type",
413
- ["Dog", "Cat", "Rabbit", "Small & Furry", "Horse", "Bird", "Scales, Fins & Other", "Barnyard"]
414
- )
415
-
416
- location = st.text_input("Location (ZIP code or City, State)", "")
417
-
418
  distance = st.slider("Distance (miles)", min_value=10, max_value=500, value=50, step=10)
419
-
420
- with col2:
421
- age_options = ["", "Baby", "Young", "Adult", "Senior"]
422
- age = st.selectbox("Age", age_options)
423
-
424
- size_options = ["", "Small", "Medium", "Large", "XLarge"]
425
- size = st.selectbox("Size", size_options)
426
-
427
- gender_options = ["", "Male", "Female"]
428
- gender = st.selectbox("Gender", gender_options)
429
- good_with_children = st.checkbox("Good with children")
430
- good_with_dogs = st.checkbox("Good with dogs")
431
- good_with_cats = st.checkbox("Good with cats")
432
- house_trained = st.checkbox("House-trained")
433
- special_needs = st.checkbox("Special needs")
434
-
435
  submitted = st.form_submit_button("Search")
436
-
437
  if submitted:
438
- # Build search parameters
439
- params = {
440
- "type": animal_type.split(" ")[0], # Take first word for types like "Small & Furry"
441
- "location": location,
442
- "distance": distance,
443
- "status": "adoptable",
444
- "sort": "distance",
445
- "limit": 100
446
- }
447
-
448
- if age and age != "":
449
- params["age"] = age
450
- if size and size != "":
451
- params["size"] = size
452
- if gender and gender != "":
453
- params["gender"] = gender
454
-
455
- # Add advanced filters
456
- if good_with_children:
457
- params["good_with_children"] = 1
458
- if good_with_dogs:
459
- params["good_with_dogs"] = 1
460
- if good_with_cats:
461
- params["good_with_cats"] = 1
462
- if house_trained:
463
- params["house_trained"] = 1
464
- if special_needs:
465
- params["special_needs"] = 1
466
-
467
- # Perform search
468
  results = search_pets(params)
469
  if results and 'animals' in results:
470
  st.session_state.search_results = results
471
  st.session_state.page = 1
472
  st.success(f"Found {len(results['animals'])} pets!")
473
- else:
474
- st.error("No pets found with those criteria. Try expanding your search.")
475
-
476
- # Display search results
477
  if st.session_state.search_results and 'animals' in st.session_state.search_results:
478
  st.markdown("### Search Results")
479
-
480
- # Pagination
481
  results = st.session_state.search_results['animals']
482
- total_pages = (len(results) + 9) // 10 # 10 items per page
483
-
484
- # Display page selector
485
- if total_pages > 1:
486
- col1, col2, col3 = st.columns([1, 3, 1])
487
- with col2:
488
- page = st.slider("Page", 1, total_pages, st.session_state.page)
489
- if page != st.session_state.page:
490
- st.session_state.page = page
491
-
492
- # Display pets for current page
493
- start_idx = (st.session_state.page - 1) * 10
494
- end_idx = min(start_idx + 10, len(results))
495
-
496
- for pet in results[start_idx:end_idx]:
497
  st.markdown("---")
498
  display_pet_card(pet)
499
-
500
- with tab2:
501
- st.markdown("### Your Favorite Pets")
502
-
503
- if not st.session_state.favorites:
504
- st.info("You haven't added any pets to your favorites yet. Start searching to find your perfect match!")
505
- else:
506
- for pet in st.session_state.favorites:
507
- st.markdown("---")
508
- display_pet_card(pet, is_favorite=True)
509
-
510
- with tab3:
511
- st.markdown("### About PetMatch")
512
- st.markdown("""
513
- PetMatch helps you find your perfect pet companion from thousands of adoptable animals across the country.
514
-
515
- **How to use PetMatch:**
516
- 1. Search for pets based on your preferences and location
517
- 2. Browse through the results and click "View Details" to learn more about each pet
518
- 3. Add pets to your favorites to keep track of the ones you're interested in
519
- 4. Contact the shelter or rescue organization directly using the provided information
520
-
521
- **Data Source:**
522
- PetMatch uses the Petfinder API to provide up-to-date information on adoptable pets. Petfinder is North America's largest adoption website with hundreds of thousands of adoptable pets listed by more than 11,500 animal shelters and rescue organizations.
523
-
524
- **Privacy:**
525
- PetMatch does not store any personal information or search history. Your favorites are stored locally in your browser and are not shared with any third parties.
526
- """)
527
-
528
- st.markdown("### Made with ❤️ by Claude")
529
 
530
  if __name__ == "__main__":
531
- main()
 
1
  import streamlit as st
2
  import requests
 
 
 
3
  import time
4
  import os
5
 
 
54
  """, unsafe_allow_html=True)
55
 
56
  # Initialize session state variables
57
+ for key, value in {'access_token': None, 'token_expires': 0, 'search_results': None, 'selected_pet': None, 'page': 1, 'favorites': []}.items():
58
+ if key not in st.session_state:
59
+ st.session_state[key] = value
 
 
 
 
 
 
 
 
 
60
 
61
  # Function to get access token
62
  def get_access_token():
 
63
  if st.session_state.access_token and time.time() < st.session_state.token_expires:
64
  return st.session_state.access_token
65
+
 
66
  api_key = os.environ.get('PETFINDER_API_KEY') or st.secrets.get('PETFINDER_API_KEY')
67
  api_secret = os.environ.get('PETFINDER_API_SECRET') or st.secrets.get('PETFINDER_API_SECRET')
68
+
69
  if not api_key or not api_secret:
70
+ st.error("⚠️ Petfinder API credentials are missing.")
71
  return None
72
+
 
73
  url = "https://api.petfinder.com/v2/oauth2/token"
74
+ data = {"grant_type": "client_credentials", "client_id": api_key, "client_secret": api_secret}
75
+
 
 
 
 
76
  try:
77
  response = requests.post(url, data=data)
78
  response.raise_for_status()
79
  token_data = response.json()
80
  st.session_state.access_token = token_data['access_token']
81
+ st.session_state.token_expires = time.time() + token_data['expires_in'] - 60
82
  return st.session_state.access_token
83
  except requests.exceptions.RequestException as e:
84
  st.error(f"⚠️ Error getting access token: {str(e)}")
 
89
  token = get_access_token()
90
  if not token:
91
  return None
 
92
  url = "https://api.petfinder.com/v2/animals"
93
  headers = {"Authorization": f"Bearer {token}"}
 
94
  try:
95
  response = requests.get(url, headers=headers, params=params)
96
  response.raise_for_status()
 
99
  st.error(f"⚠️ Error searching pets: {str(e)}")
100
  return None
101
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  # Function to get pet details
103
  def get_pet_details(pet_id):
104
  token = get_access_token()
105
  if not token:
106
  return None
 
107
  url = f"https://api.petfinder.com/v2/animals/{pet_id}"
108
  headers = {"Authorization": f"Bearer {token}"}
 
109
  try:
110
  response = requests.get(url, headers=headers)
111
  response.raise_for_status()
 
117
  # Function to format pet card
118
  def display_pet_card(pet, is_favorite=False):
119
  col1, col2 = st.columns([1, 2])
 
120
  with col1:
121
  if pet['photos'] and len(pet['photos']) > 0:
122
  st.image(pet['photos'][0]['medium'], use_container_width=True)
123
  else:
124
  st.image("https://via.placeholder.com/300x300?text=No+Image", use_container_width=True)
125
+
126
  with col2:
127
  st.markdown(f"<div class='pet-name'>{pet['name']}</div>", unsafe_allow_html=True)
 
 
128
  tags_html = ""
129
  if pet['status'] == 'adoptable':
130
  tags_html += "<span class='tag' style='background-color: #c8e6c9;'>Adoptable</span> "
131
  else:
132
  tags_html += f"<span class='tag' style='background-color: #ffcdd2;'>{pet['status'].title()}</span> "
 
133
  if pet['age']:
134
  tags_html += f"<span class='tag'>{pet['age']}</span> "
135
  if pet['gender']:
136
  tags_html += f"<span class='tag'>{pet['gender']}</span> "
137
  if pet['size']:
138
  tags_html += f"<span class='tag'>{pet['size']}</span> "
 
139
  st.markdown(f"<div>{tags_html}</div>", unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
 
141
+ if st.button("View Details", key=f"details_{pet['id']}"):
142
+ if st.session_state.selected_pet != pet['id']:
143
+ st.session_state.selected_pet = pet['id']
144
+ st.experimental_rerun()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
 
146
  # Function to display pet details page
147
  def display_pet_details(pet_id):
148
  pet = get_pet_details(pet_id)
149
  if not pet:
150
+ st.error("Unable to retrieve pet details.")
151
  return
 
 
152
  if st.button("← Back to Search Results"):
153
  if st.session_state.selected_pet is not None:
154
  st.session_state.selected_pet = None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
  st.experimental_rerun()
156
+ st.markdown(f"<h1 class='main-header'>{pet['name']}</h1>", unsafe_allow_html=True)
157
 
158
  # Main app
159
  def main():
 
160
  st.markdown("<h1 class='main-header'>🐾 PetMatch</h1>", unsafe_allow_html=True)
161
  st.markdown("<p class='sub-header'>Find your perfect pet companion</p>", unsafe_allow_html=True)
 
 
162
  tab1, tab2, tab3 = st.tabs(["Search", "Favorites", "About"])
 
163
  with tab1:
 
164
  if st.session_state.selected_pet:
165
  display_pet_details(st.session_state.selected_pet)
166
  else:
 
167
  with st.expander("Search Options", expanded=True):
168
  with st.form("pet_search_form"):
169
  col1, col2 = st.columns(2)
 
170
  with col1:
171
+ animal_type = st.selectbox("Animal Type", ["Dog", "Cat"])
172
+ location = st.text_input("Location", "")
 
 
 
 
 
173
  distance = st.slider("Distance (miles)", min_value=10, max_value=500, value=50, step=10)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
  submitted = st.form_submit_button("Search")
 
175
  if submitted:
176
+ params = {"type": animal_type, "location": location, "distance": distance, "status": "adoptable"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
  results = search_pets(params)
178
  if results and 'animals' in results:
179
  st.session_state.search_results = results
180
  st.session_state.page = 1
181
  st.success(f"Found {len(results['animals'])} pets!")
 
 
 
 
182
  if st.session_state.search_results and 'animals' in st.session_state.search_results:
183
  st.markdown("### Search Results")
 
 
184
  results = st.session_state.search_results['animals']
185
+ for pet in results:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186
  st.markdown("---")
187
  display_pet_card(pet)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
 
189
  if __name__ == "__main__":
190
+ main()