Ask-FashionDB / app.py
traopia
ask fashiondb
69fe46f
import gradio as gr
import pandas as pd
import numpy as np
from search import search_images_by_text, get_similar_images, search_images_by_image
import requests
from io import BytesIO
def create_collection_url(row):
base_url = "https://www.vogue.com/fashion-shows/"
season = str(row["season"]).lower()
year = str(row["year"])
category = str(row["category"]).lower() if pd.notna(row["category"]) and row["category"] and str(row["category"]).lower() != "nan" else None
designer = str(row["designer"]).lower().replace(" ", "-")
# Add city if available
city = str(row["city"]).lower().replace(" ", "-") if pd.notna(row["city"]) and row["city"] and str(row["city"]).lower() != "nan" else None
if pd.isna(category) or category is None or category == "nan":
if city:
return f"{base_url}{city}-{season}-{year}/{designer}"
else:
return f"{base_url}{season}-{year}/{designer}"
else:
if city:
return f"{base_url}{city}-{season}-{year}-{category}/{designer}"
else:
return f"{base_url}{season}-{year}-{category}/{designer}"
import requests
from io import BytesIO
#@st.cache_data(show_spinner="Loading FashionDB...")
def load_data_hf():
# Load the Parquet file directly from Hugging Face
df_url = "https://huggingface.co/datasets/traopia/vogue-runway/resolve/main/VogueRunway.parquet"
df = pd.read_parquet(df_url)
# Load the .npy file using requests
npy_url = "https://huggingface.co/datasets/traopia/vogue-runway/resolve/main/VogueRunway_image.npy"
response = requests.get(npy_url)
response.raise_for_status() # Raise error if download fails
embeddings = np.load(BytesIO(response.content))
df['collection'] = df.apply(create_collection_url, axis=1)
return df, embeddings
df, embeddings = load_data_hf()
# Filter and search
def filter_and_search(fashion_house, category, season, start_year, end_year, query):
filtered = df.copy()
if fashion_house:
filtered = filtered[filtered['designer'].isin(fashion_house)]
if category:
filtered = filtered[filtered['category'].isin(category)]
if season:
filtered = filtered[filtered['season'].isin(season)]
filtered = filtered[(filtered['year'] >= start_year) & (filtered['year'] <= end_year)]
if query:
results = search_images_by_text(query, filtered, embeddings)
else:
results = filtered.head(30)
image_urls = results["url"].tolist()
metadata = results.to_dict(orient="records")
return image_urls, metadata
# Display metadata and similar
def show_metadata(idx, metadata):
item = metadata[idx]
out = ""
for field in ["designer", "season", "year", "category"]:
if field in item and pd.notna(item[field]):
out += f"**{field.title()}**: {item[field]}\n"
if 'collection' in item and pd.notna(item['collection']):
out += f"\n[View Collection]({item['collection']})"
return out
def find_similar(idx, metadata):
if not isinstance(idx, int) or idx >= len(metadata) or idx < 0:
return [] # or gr.update(visible=False)
key = metadata[idx]["key"]
similar_df = get_similar_images(df, key, embeddings, top_k=5)
return similar_df["url"].tolist(), similar_df.to_dict(orient="records")
with gr.Blocks() as demo:
gr.Markdown("# 👗 FashionDB Explorer")
with gr.Tabs():
# TEXT SEARCH TAB
with gr.Tab("Search by Text"):
with gr.Row():
fashion_house = gr.Dropdown(label="Fashion House", choices=sorted(df["designer"].dropna().unique()), multiselect=True)
category = gr.Dropdown(label="Category", choices=sorted(df["category"].dropna().unique()), multiselect=True)
season = gr.Dropdown(label="Season", choices=sorted(df["season"].dropna().unique()), multiselect=True)
min_year = int(df['year'].min())
max_year = int(df['year'].max())
start_year = gr.Slider(label="Start Year", minimum=min_year, maximum=max_year, value=2000, step=1)
end_year = gr.Slider(label="End Year", minimum=min_year, maximum=max_year, value=2024, step=1)
query = gr.Textbox(label="Search by text", placeholder="e.g., pink dress")
search_button = gr.Button("Search")
result_gallery = gr.Gallery(label="Search Results", columns=5, height="auto")
metadata_output = gr.Markdown()
reference_image = gr.Image(label="Reference Image", interactive=False)
similar_gallery = gr.Gallery(label="Similar Images", columns=5, height="auto")
metadata_state = gr.State([])
selected_idx = gr.Number(value=0, visible=False)
def handle_search(fh, cat, sea, sy, ey, q):
imgs, meta = filter_and_search(fh, cat, sea, sy, ey, q)
return imgs, meta, "", [], None
search_button.click(
handle_search,
inputs=[fashion_house, category, season, start_year, end_year, query],
outputs=[result_gallery, metadata_state, metadata_output, similar_gallery, reference_image]
)
def handle_click(evt: gr.SelectData, metadata):
idx = evt.index
md = show_metadata(idx, metadata)
img_path = metadata[idx]["url"]
return idx, md, img_path
result_gallery.select(
handle_click,
inputs=[metadata_state],
outputs=[selected_idx, metadata_output, reference_image]
)
def show_similar(idx, metadata):
if idx is None or not str(idx).isdigit():
return [], []
return find_similar(int(idx), metadata)
similar_metadata_state = gr.State()
similar_metadata_output = gr.Markdown()
show_similar_button = gr.Button("Show Similar Images")
show_similar_button.click(
show_similar,
inputs=[selected_idx, metadata_state],
outputs=[similar_gallery, similar_metadata_state]
)
def handle_similar_click(evt: gr.SelectData, metadata):
idx = evt.index
md = show_metadata(idx, metadata)
img_path = metadata[idx]["url"]
return idx, md, img_path
similar_gallery.select(
handle_similar_click,
inputs=[similar_metadata_state],
outputs=[selected_idx, similar_metadata_output, reference_image]
)
# IMAGE SEARCH TAB
with gr.Tab("Search by Image"):
with gr.Row():
fashion_house_img = gr.Dropdown(label="Fashion House", choices=sorted(df["designer"].dropna().unique()), multiselect=True)
category_img = gr.Dropdown(label="Category", choices=sorted(df["category"].dropna().unique()), multiselect=True)
season_img = gr.Dropdown(label="Season", choices=sorted(df["season"].dropna().unique()), multiselect=True)
start_year_img = gr.Slider(label="Start Year", minimum=min_year, maximum=max_year, value=2000, step=1)
end_year_img = gr.Slider(label="End Year", minimum=min_year, maximum=max_year, value=2024, step=1)
uploaded_image = gr.Image(label="Upload an image", type="pil")
search_by_image_button = gr.Button("Search by Image")
uploaded_result_gallery = gr.Gallery(label="Search Results by Image", columns=5, height="auto")
uploaded_metadata_state = gr.State([])
uploaded_metadata_output = gr.Markdown()
uploaded_reference_image = gr.Image(label="Reference Image", interactive=False)
def handle_search_by_image(image, fh, cat, sea, sy, ey):
if image is None:
return [], "Please upload an image first.", None
# Apply filters
filtered_df = df.copy()
if fh: filtered_df = filtered_df[filtered_df["designer"].isin(fh)]
if cat: filtered_df = filtered_df[filtered_df["category"].isin(cat)]
if sea: filtered_df = filtered_df[filtered_df["season"].isin(sea)]
filtered_df = filtered_df[(filtered_df["year"] >= sy) & (filtered_df["year"] <= ey)]
results_df = search_images_by_image(image, filtered_df, embeddings)
images = results_df['url'].tolist()
metadata = results_df.to_dict(orient="records")
return images, metadata, ""
search_by_image_button.click(
handle_search_by_image,
inputs=[uploaded_image, fashion_house_img, category_img, season_img, start_year_img, end_year_img],
outputs=[uploaded_result_gallery, uploaded_metadata_state, uploaded_metadata_output]
)
uploaded_selected_idx = gr.Number(visible=False)
def handle_uploaded_click(evt: gr.SelectData, metadata):
idx = evt.index
md = show_metadata(idx, metadata)
img_path = metadata[idx]["url"]
return idx, md, img_path
uploaded_result_gallery.select(
handle_uploaded_click,
inputs=[uploaded_metadata_state],
outputs=[uploaded_selected_idx, uploaded_metadata_output, uploaded_reference_image]
)
# SIMILAR IMAGE SEARCH FOR IMAGE TAB
uploaded_similar_gallery = gr.Gallery(label="Similar Images", columns=5, height="auto")
uploaded_similar_metadata_state = gr.State([])
uploaded_similar_metadata_output = gr.Markdown()
uploaded_show_similar_button = gr.Button("Show Similar Images")
def show_similar_uploaded(idx, metadata):
if idx is None or not str(idx).isdigit():
return [], []
return find_similar(int(idx), metadata)
uploaded_show_similar_button.click(
show_similar_uploaded,
inputs=[uploaded_selected_idx, uploaded_metadata_state],
outputs=[uploaded_similar_gallery, uploaded_similar_metadata_state]
)
def handle_uploaded_similar_click(evt: gr.SelectData, metadata):
idx = evt.index
md = show_metadata(idx, metadata)
img_path = metadata[idx]["url"]
return idx, md, img_path
uploaded_similar_gallery.select(
handle_uploaded_similar_click,
inputs=[uploaded_similar_metadata_state],
outputs=[uploaded_selected_idx, uploaded_similar_metadata_output, uploaded_reference_image]
)
uploaded_back_button = gr.Button("Back to Initial Uploaded Search")
def back_to_uploaded_home():
return [], "", None
uploaded_back_button.click(
back_to_uploaded_home,
outputs=[uploaded_similar_gallery, uploaded_similar_metadata_output, uploaded_reference_image]
)
with gr.Tab("Query on FashionDB"):
with gr.Row():
gr.Markdown(
"### 🔗 Query FashionDB SPARQL Endpoint\n"
"[Click here to open the SPARQL endpoint](https://fashionwiki.wikibase.cloud/query/)",
elem_id="sparql-link"
)
back_button = gr.Button("Back to Home")
def back_to_home():
return [], "", None # clear similar_gallery, metadata_output, reference image
back_button.click(
back_to_home,
outputs=[similar_gallery, similar_metadata_output, reference_image]
)
demo.launch()