|
import requests |
|
import random |
|
import gradio as gr |
|
import time |
|
|
|
max_results = 200 |
|
|
|
|
|
cache = {} |
|
|
|
|
|
component_templates = [ |
|
"All templates", |
|
"SimpleDropdown", |
|
"SimpleTextbox", |
|
"SimpleImage", |
|
"Audio", |
|
"BarPlot", |
|
"Button", |
|
"Chatbot", |
|
"ClearButton", |
|
"Checkbox", |
|
"CheckboxGroup", |
|
"Code", |
|
"ColorPicker", |
|
"DataFrame", |
|
"DownloadButton", |
|
"DuplicateButton", |
|
"Gallery", |
|
"HTML", |
|
"FileExplorer", |
|
"Image", |
|
"JSON", |
|
"Label", |
|
"LinePlot", |
|
"LoginButton", |
|
"LogoutButton", |
|
"Markdown", |
|
"Textbox", |
|
"DateTime", |
|
"Dropdown", |
|
"Model3D", |
|
"File", |
|
"HighlightedText", |
|
"AnnotatedImage", |
|
"CheckboxGroup", |
|
"Number", |
|
"Plot", |
|
"Radio", |
|
"ScatterPlot", |
|
"Slider", |
|
"Timer", |
|
"UploadButton", |
|
"Video", |
|
"ImageEditor", |
|
"ParamViewer", |
|
"MultimodalTextbox", |
|
"NativePlot", |
|
"Accordion", |
|
"Column", |
|
"Row", |
|
"Group", |
|
"Tabs", |
|
"Tab", |
|
"TabItem" |
|
] |
|
|
|
|
|
sort_by_options = [ |
|
"Most likes", |
|
"Recently created", |
|
"Recently updated" |
|
] |
|
|
|
|
|
background_colors = [ |
|
'var(--color-blue-300)', |
|
'var(--color-red-300)', |
|
'var(--color-yellow-200)', |
|
'var(--color-green-200)', |
|
'var(--color-orange-200)' |
|
] |
|
|
|
def fetch_space_details(subdomain): |
|
""" |
|
Function to fetch details for a specific component using its subdomain. |
|
Uses cache to avoid redundant API requests. |
|
""" |
|
if subdomain in cache: |
|
return cache[subdomain] |
|
|
|
try: |
|
api_url = f"https://huggingface.co/api/spaces/by-subdomain/{subdomain}" |
|
response = requests.get(api_url) |
|
if response.status_code == 200: |
|
data = response.json() |
|
cache[subdomain] = data |
|
return data |
|
else: |
|
return None |
|
except Exception as e: |
|
raise gr.Error(f"Error fetching details for {subdomain}: {e}") |
|
return None |
|
|
|
def fetch_results(search_query, sort_query, template_query): |
|
""" |
|
Function to fetch results from API based on search term |
|
""" |
|
try: |
|
api_url = f"https://gradio-custom-component-gallery-backend.hf.space/components?name_or_tags={search_query}" |
|
response = requests.get(api_url) |
|
results = response.json() |
|
|
|
num_results = len(results) |
|
|
|
if num_results < 1: |
|
raise gr.Error("No results found") |
|
else: |
|
print(f"Received {num_results} results") |
|
|
|
|
|
detailed_results = [] |
|
for component in results[:max_results]: |
|
subdomain = component.get('subdomain', '') |
|
details = fetch_space_details(subdomain) |
|
if details: |
|
component['createdAt'] = details.get('createdAt', 'N/A') |
|
component['lastModified'] = details.get('lastModified', 'N/A') |
|
detailed_results.append(component) |
|
|
|
|
|
if sort_query == "Recently created": |
|
detailed_results.sort(key=lambda x: x.get('createdAt', ''), reverse=True) |
|
elif sort_query == "Recently updated": |
|
detailed_results.sort(key=lambda x: x.get('lastModified', ''), reverse=True) |
|
elif sort_query == "Most likes": |
|
detailed_results.sort(key=lambda x: x.get('likes', 0), reverse=True) |
|
|
|
updates = [] |
|
|
|
|
|
for index, component in enumerate(detailed_results): |
|
id = component.get('id', 'N/A') |
|
name = component.get('name', 'N/A') |
|
author = component.get('author', 'N/A') |
|
tags = component.get('tags', '') |
|
version = component.get('version', 'N/A') |
|
template = component.get('template', '') |
|
description = component.get('description', 'No description available') |
|
subdomain = component.get('subdomain', '') |
|
likes = component.get('likes', 0) |
|
created_at = component.get('createdAt', 'N/A') |
|
last_modified = component.get('lastModified', 'N/A') |
|
|
|
|
|
background_color = random.choice(background_colors) |
|
|
|
|
|
html = f''' |
|
<a href="https://huggingface.co/spaces/{id}" target=”_blank”> |
|
<div style="width: 290px; height: 160px; padding: 15px; background-color: {background_color}; border: 1px solid var(--border-color-primary); border-radius: 12px; box-shadow: 0px 0px 3px rgba(0, 0, 0, 0.1); font-family: Arial, sans-serif; position: relative;"> |
|
<!-- Title --> |
|
<div style="font-weight: var(--weight-bold); font-size: var(--text-lg); color: var(--neutral-950);"> |
|
{name} |
|
</div> |
|
|
|
<!-- Description --> |
|
<div style="height: 72px; font-size: var(--text-md); color: var(--neutral-900); margin-top: 5px;"> |
|
{description} |
|
</div> |
|
|
|
<!-- Author --> |
|
<div style="font-size: var(--text-sm); color: var(--accordion-text-color); margin-top: 10px; background-color: var(--background-fill-secondary); display: inline-block; padding: 5px 10px; border-radius: var(--radius-xl);"> |
|
@{author} |
|
</div> |
|
|
|
<!-- Like button with heart and count --> |
|
<div style="position: absolute; top: var(--spacing-xl); right: var(--spacing-xl); display: flex; align-items: center; justify-content: center; background-color: var(--background-fill-secondary); color: var(--accordion-text-color); padding: 5px 10px; border-radius: var(--radius-xl);"> |
|
<div style="font-size: var(--text-sm); color: var(--accordion-text-color); padding-right: 3px;">♡</div> <!-- Heart icon --> |
|
<div style="font-size: var(--text-md); color: var(--accordion-text-color); margin-right: 5px;">{likes}</div> |
|
</div> |
|
</div> |
|
</a> |
|
''' |
|
|
|
|
|
result_row_update = gr.update( |
|
visible=( |
|
True if template_query == component_templates[0] |
|
else True if template_query == template |
|
else False |
|
) |
|
) |
|
result_update = gr.update( |
|
value=html, |
|
visible=( |
|
True if template_query == component_templates[0] |
|
else True if template_query == template |
|
else False |
|
) |
|
) |
|
|
|
|
|
updates.extend([result_row_update, result_update]) |
|
|
|
|
|
for i in range(len(detailed_results), max_results): |
|
updates.extend([ |
|
gr.update(visible=False), |
|
gr.update(visible=False), |
|
]) |
|
|
|
|
|
results_area_update = gr.update(visible=True) |
|
updates.append(results_area_update) |
|
|
|
hide_spinner = gr.update(visible=False) |
|
|
|
return updates |
|
|
|
except Exception as e: |
|
raise gr.Error(f"{e}") |
|
|
|
|
|
with gr.Blocks( |
|
css=""" |
|
a {text-decoration-line: none !important;} |
|
.form {border: none !important;} |
|
.search-row {display: flex; align-items: center !important; gap: 0 !important; margin: 24px 0px 0px 0px;} |
|
.result-row {min-width: 292px !important; max-width: 200px !important;} |
|
.result-column {min-width: 292px !important; max-width: 200px !important;} |
|
.search-input {background: var(--background-fill-secondary) !important;} |
|
.sort-input {background: var(--background-fill-secondary) !important;} |
|
.template-input {background: var(--background-fill-secondary) !important;} |
|
.result {overflow: hidden !important;} |
|
""" |
|
) as demo: |
|
result_rows = [] |
|
results = [] |
|
|
|
with gr.Column(): |
|
with gr.Row(elem_classes="panel-row", variant="panel"): |
|
with gr.Column(elem_classes="search-column"): |
|
with gr.Row(elem_classes="search-row"): |
|
search_input = gr.Textbox(placeholder="Search", elem_classes="search-input", show_label=False, max_lines=1, scale=1) |
|
search_button = gr.Button("Search", scale=0) |
|
with gr.Column(elem_classes="filter-column"): |
|
with gr.Row(elem_classes="filter-row"): |
|
sort_input = gr.Dropdown(label="Sort by", value=sort_by_options[0], choices=sort_by_options, elem_classes="sort-input", interactive=True) |
|
template_input = gr.Dropdown(label="Template", value=component_templates[0], choices=component_templates, elem_classes="template-input", interactive=True) |
|
|
|
with gr.Row(elem_classes="results") as results_area: |
|
for i in range(max_results): |
|
with gr.Row(visible=False, elem_classes="result-row") as result_row: |
|
with gr.Column(elem_classes="result-column"): |
|
result = gr.HTML("", elem_classes="result") |
|
result_rows.append(result_row) |
|
results.append(result) |
|
|
|
|
|
outputs = [] |
|
for i in range(max_results): |
|
outputs.extend([result_rows[i], results[i]]) |
|
outputs.append(results_area) |
|
|
|
|
|
gr.on( |
|
triggers=[search_input.submit, search_button.click, sort_input.change, template_input.change, demo.load], |
|
fn=fetch_results, |
|
inputs=[search_input, sort_input, template_input], |
|
outputs=outputs |
|
) |
|
|
|
demo.launch() |