Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -266,11 +266,12 @@ def flickr_api_call(method, **params):
|
|
| 266 |
return data
|
| 267 |
|
| 268 |
|
| 269 |
-
def flickr_search(search_text, max_images=50, min_width=0, min_height=0
|
|
|
|
| 270 |
if not FLICKR_API_KEY:
|
| 271 |
raise RuntimeError("No FLICKR_API_KEY found. Add it under Space Settings β Secrets.")
|
| 272 |
search_text = search_text.strip()
|
| 273 |
-
if not search_text:
|
| 274 |
raise ValueError("No Flickr search term was found.")
|
| 275 |
|
| 276 |
max_images = min(int(max_images), MAX_IMAGES_HARD_LIMIT)
|
|
@@ -280,8 +281,10 @@ def flickr_search(search_text, max_images=50, min_width=0, min_height=0):
|
|
| 280 |
|
| 281 |
while len(results) < max_images:
|
| 282 |
data = flickr_api_call(
|
| 283 |
-
|
| 284 |
-
text
|
|
|
|
|
|
|
| 285 |
extras="description,license,date_upload,date_taken,owner_name,tags,views,"
|
| 286 |
"url_sq,url_t,url_s,url_q,url_m,url_n,url_z,url_c,url_l,url_o,"
|
| 287 |
"o_dims,original_format",
|
|
@@ -416,6 +419,25 @@ def flickr_photo_candidate(url):
|
|
| 416 |
return flickr_photo_via_html(username, photo_id, page_url)
|
| 417 |
|
| 418 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 419 |
# ============================================================
|
| 420 |
# GENERIC HTML
|
| 421 |
# ============================================================
|
|
@@ -699,7 +721,7 @@ def empty_result(message):
|
|
| 699 |
return [], message, [], pd.DataFrame(), pd.DataFrame(), None, None, None
|
| 700 |
|
| 701 |
|
| 702 |
-
def find_images(url, max_images, min_width, min_height, remove_duplicates):
|
| 703 |
url = clean_url(url)
|
| 704 |
if not url:
|
| 705 |
return empty_result("β Please enter a URL.")
|
|
@@ -715,10 +737,16 @@ def find_images(url, max_images, min_width, min_height, remove_duplicates):
|
|
| 715 |
|
| 716 |
# ---- Find candidates ----
|
| 717 |
try:
|
| 718 |
-
|
| 719 |
-
|
| 720 |
-
|
| 721 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 722 |
elif is_flickr_url(url) and FLICKR_API_KEY and extract_flickr_search_text(url):
|
| 723 |
mode_message = "Flickr API search mode"
|
| 724 |
candidates = flickr_search(
|
|
@@ -880,6 +908,10 @@ with gr.Blocks(title=APP_TITLE) as demo:
|
|
| 880 |
min_width = gr.Number(value=0, minimum=0, maximum=10000, step=100, label="Minimum width (px)")
|
| 881 |
min_height = gr.Number(value=0, minimum=0, maximum=10000, step=100, label="Minimum height (px)")
|
| 882 |
remove_duplicates = gr.Checkbox(value=True, label="Remove duplicates")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 883 |
|
| 884 |
with gr.Row():
|
| 885 |
find_button = gr.Button("π Find & Analyze Images", variant="primary")
|
|
@@ -913,7 +945,7 @@ with gr.Blocks(title=APP_TITLE) as demo:
|
|
| 913 |
|
| 914 |
find_button.click(
|
| 915 |
fn=find_images,
|
| 916 |
-
inputs=[url_input, max_images, min_width, min_height, remove_duplicates],
|
| 917 |
outputs=[gallery, status, image_state, metadata_table, weekly_table,
|
| 918 |
weekly_plot, xlsx_file, csv_file],
|
| 919 |
)
|
|
|
|
| 266 |
return data
|
| 267 |
|
| 268 |
|
| 269 |
+
def flickr_search(search_text, max_images=50, min_width=0, min_height=0,
|
| 270 |
+
method="flickr.photos.search", extra_params=None):
|
| 271 |
if not FLICKR_API_KEY:
|
| 272 |
raise RuntimeError("No FLICKR_API_KEY found. Add it under Space Settings β Secrets.")
|
| 273 |
search_text = search_text.strip()
|
| 274 |
+
if method == "flickr.photos.search" and not search_text:
|
| 275 |
raise ValueError("No Flickr search term was found.")
|
| 276 |
|
| 277 |
max_images = min(int(max_images), MAX_IMAGES_HARD_LIMIT)
|
|
|
|
| 281 |
|
| 282 |
while len(results) < max_images:
|
| 283 |
data = flickr_api_call(
|
| 284 |
+
method,
|
| 285 |
+
**({"text": search_text} if method == "flickr.photos.search" else {}),
|
| 286 |
+
**(extra_params or {}),
|
| 287 |
+
safe_search="1", per_page=per_page, page=page,
|
| 288 |
extras="description,license,date_upload,date_taken,owner_name,tags,views,"
|
| 289 |
"url_sq,url_t,url_s,url_q,url_m,url_n,url_z,url_c,url_l,url_o,"
|
| 290 |
"o_dims,original_format",
|
|
|
|
| 419 |
return flickr_photo_via_html(username, photo_id, page_url)
|
| 420 |
|
| 421 |
|
| 422 |
+
def flickr_photo_and_stream(url, max_images, min_width, min_height, include_stream=True):
|
| 423 |
+
"""Photo page -> the photo itself, then the same photographer's older public photos."""
|
| 424 |
+
first = flickr_photo_candidate(url)
|
| 425 |
+
if not first:
|
| 426 |
+
return None
|
| 427 |
+
if not (include_stream and FLICKR_API_KEY and max_images > 1):
|
| 428 |
+
return [first]
|
| 429 |
+
info = flickr_api_call("flickr.photos.getInfo", photo_id=first["photo_id"])["photo"]
|
| 430 |
+
stream = flickr_search(
|
| 431 |
+
"", max_images, min_width, min_height,
|
| 432 |
+
method="flickr.people.getPublicPhotos",
|
| 433 |
+
extra_params={
|
| 434 |
+
"user_id": info["owner"]["nsid"],
|
| 435 |
+
"max_upload_date": info["dates"]["posted"], # start at this photo, go older
|
| 436 |
+
},
|
| 437 |
+
)
|
| 438 |
+
return [first] + [s for s in stream if s["photo_id"] != first["photo_id"]]
|
| 439 |
+
|
| 440 |
+
|
| 441 |
# ============================================================
|
| 442 |
# GENERIC HTML
|
| 443 |
# ============================================================
|
|
|
|
| 721 |
return [], message, [], pd.DataFrame(), pd.DataFrame(), None, None, None
|
| 722 |
|
| 723 |
|
| 724 |
+
def find_images(url, max_images, min_width, min_height, remove_duplicates, include_stream=True):
|
| 725 |
url = clean_url(url)
|
| 726 |
if not url:
|
| 727 |
return empty_result("β Please enter a URL.")
|
|
|
|
| 737 |
|
| 738 |
# ---- Find candidates ----
|
| 739 |
try:
|
| 740 |
+
photo_list = (
|
| 741 |
+
flickr_photo_and_stream(url, max_images, min_width, min_height, include_stream)
|
| 742 |
+
if is_flickr_url(url) else None
|
| 743 |
+
)
|
| 744 |
+
if photo_list:
|
| 745 |
+
mode_message = (
|
| 746 |
+
"Flickr photo page + photostream (API)" if FLICKR_API_KEY
|
| 747 |
+
else "Flickr photo page (HTML, single photo only: set FLICKR_API_KEY to get more)"
|
| 748 |
+
)
|
| 749 |
+
candidates = photo_list
|
| 750 |
elif is_flickr_url(url) and FLICKR_API_KEY and extract_flickr_search_text(url):
|
| 751 |
mode_message = "Flickr API search mode"
|
| 752 |
candidates = flickr_search(
|
|
|
|
| 908 |
min_width = gr.Number(value=0, minimum=0, maximum=10000, step=100, label="Minimum width (px)")
|
| 909 |
min_height = gr.Number(value=0, minimum=0, maximum=10000, step=100, label="Minimum height (px)")
|
| 910 |
remove_duplicates = gr.Checkbox(value=True, label="Remove duplicates")
|
| 911 |
+
include_stream = gr.Checkbox(
|
| 912 |
+
value=True,
|
| 913 |
+
label="Photo page: also download the photographer's other photos (needs API key)",
|
| 914 |
+
)
|
| 915 |
|
| 916 |
with gr.Row():
|
| 917 |
find_button = gr.Button("π Find & Analyze Images", variant="primary")
|
|
|
|
| 945 |
|
| 946 |
find_button.click(
|
| 947 |
fn=find_images,
|
| 948 |
+
inputs=[url_input, max_images, min_width, min_height, remove_duplicates, include_stream],
|
| 949 |
outputs=[gallery, status, image_state, metadata_table, weekly_table,
|
| 950 |
weekly_plot, xlsx_file, csv_file],
|
| 951 |
)
|