import html
from datetime import datetime, timezone
import gradio as gr
import numpy as np
import pandas as pd
from sentence_transformers import SentenceTransformer
DATA_PATH = "users_ai_ml_interests_only.parquet"
EMBEDDINGS_PATH = "embeddings_ai_ml_interests.npy"
MODEL_NAME = "BAAI/bge-small-en-v1.5"
profile_df = pd.read_parquet(DATA_PATH)
profile_embeddings = np.load(EMBEDDINGS_PATH).astype(np.float32)
print(f"โ
Loaded {len(profile_df)} HF Atlas profiles from parquet")
print(f"โ
Loaded embeddings: {profile_embeddings.shape}")
if len(profile_df) != profile_embeddings.shape[0]:
raise ValueError(
f"Parquet / embeddings mismatch: {len(profile_df)} rows vs {profile_embeddings.shape[0]} embeddings"
)
def detect_username_col(df):
for col in ["user", "username", "namespace"]:
if col in df.columns:
return col
return None
USERNAME_COL = detect_username_col(profile_df)
if USERNAME_COL is None:
raise ValueError("No username column found. Expected one of: user, username, namespace")
def normalize_embeddings_if_needed(embeddings):
norms = np.linalg.norm(embeddings, axis=1, keepdims=True)
norms = np.where(norms == 0, 1.0, norms)
return embeddings / norms
profile_embeddings = normalize_embeddings_if_needed(profile_embeddings)
embedder = SentenceTransformer(MODEL_NAME)
def safe_text(value, default=""):
if value is None:
return default
try:
if pd.isna(value):
return default
except Exception:
pass
text = str(value).strip()
if text.lower() in {"nan", "none", "null"}:
return default
return text
def parse_last_seen(value):
text = safe_text(value)
if not text:
return pd.NaT
return pd.to_datetime(text, errors="coerce", utc=True)
def prepare_dates():
if "last_seen_all_repo" not in profile_df.columns:
profile_df["_last_seen_dt"] = pd.NaT
print("โ ๏ธ Column last_seen_all_repo not found. Date filter will only work as no-filter.")
return
profile_df["_last_seen_dt"] = profile_df["last_seen_all_repo"].map(parse_last_seen)
known = int(profile_df["_last_seen_dt"].notna().sum())
unknown = int(profile_df["_last_seen_dt"].isna().sum())
print(f"๐ Known last_seen_all_repo dates: {known}")
print(f"๐ณ๏ธ Unknown last_seen_all_repo dates: {unknown}")
if known > 0:
print(f"๐ Min last_seen: {profile_df['_last_seen_dt'].min()}")
print(f"๐ Max last_seen: {profile_df['_last_seen_dt'].max()}")
prepare_dates()
def filter_by_activity(df, activity_filter, custom_days):
if "_last_seen_dt" not in df.columns:
return df
custom_days = int(custom_days) if custom_days else 0
if activity_filter == "No filter":
return df
if activity_filter == "Has known activity date":
return df[df["_last_seen_dt"].notna()]
if activity_filter == "No known activity date":
return df[df["_last_seen_dt"].isna()]
if activity_filter == "Max age in days":
if custom_days <= 0:
return df
now = pd.Timestamp(datetime.now(timezone.utc))
cutoff = now - pd.Timedelta(days=custom_days)
return df[df["_last_seen_dt"].notna() & (df["_last_seen_dt"] >= cutoff)]
return df
def format_number(value):
text = safe_text(value, "0")
try:
number = int(float(text))
return f"{number:,}".replace(",", " ")
except Exception:
return html.escape(text)
def format_date(value):
text = safe_text(value)
if not text:
return "unknown"
try:
dt = pd.to_datetime(text, errors="coerce", utc=True)
if pd.isna(dt):
return "unknown"
return dt.strftime("%Y-%m-%d")
except Exception:
return html.escape(text)
def truncate(text, max_len=900):
text = safe_text(text)
if len(text) <= max_len:
return text
return text[:max_len].rsplit(" ", 1)[0] + "..."
def get_profile_url(row):
if "atlas_request_url" in row and safe_text(row["atlas_request_url"]):
return (
safe_text(row["atlas_request_url"])
.replace("/api/users/", "/")
.replace("/overview", "")
)
username = safe_text(row[USERNAME_COL])
return f"https://huggingface.co/{username}"
def render_profile_card(row, score, rank):
username = safe_text(row[USERNAME_COL], "unknown")
fullname = safe_text(row.get("fullname", ""), "")
details = safe_text(row.get("details", ""), "")
ai_ml_interests = truncate(row.get("ai_ml_interests", ""), 800)
last_seen = format_date(row.get("last_seen_all_repo", ""))
num_models = format_number(row.get("numModels", row.get("n_models", 0)))
num_datasets = format_number(row.get("numDatasets", row.get("n_datasets", 0)))
num_spaces = format_number(row.get("numSpaces", row.get("n_spaces", 0)))
followers = format_number(row.get("numFollowers", 0))
likes = format_number(row.get("numLikes", row.get("numUpvotes", 0)))
url = get_profile_url(row)
title = html.escape(username)
fullname_html = html.escape(fullname) if fullname else "โ"
details_html = html.escape(truncate(details, 300)) if details else ""
interests_html = html.escape(ai_ml_interests).replace("\n", "
")
extra_details = ""
if details_html:
extra_details = f"""
Search Hugging Face profiles by AI/ML interests and filter by public activity.
' ) query = gr.Textbox( label="Search query", placeholder="e.g. diffusion models, biomedical NLP, reinforcement learning, graph neural networks, robotics...", lines=4, ) with gr.Row(): activity_filter = gr.Dropdown( choices=[ "No filter", "Max age in days", "Has known activity date", "No known activity date", ], value="Max age in days", label="Last public activity filter", ) custom_days = gr.Number( label="Max last_seen age in days, 0 = no limit", value=365, precision=0, ) display_count_state = gr.State(value=0) submit_btn = gr.Button("๐ Search HF Atlas") output = gr.HTML() with gr.Row(elem_classes=["more-button-wrap"]): more_btn = gr.Button("โ Show more", visible=False) submit_btn.click( fn=search_hf_atlas, inputs=[query, activity_filter, custom_days], outputs=[output, display_count_state, more_btn], ) more_btn.click( fn=search_more_hf_atlas, inputs=[query, activity_filter, custom_days, display_count_state], outputs=[output, display_count_state, more_btn], ) demo.launch(css=css, theme=gr.themes.Base())